docs: public static MultiplexingDiscovery forServices(NetworkParameters params, long services) {
          List<PeerDiscovery> discoveries = Lists.newArrayList();
          HttpDiscovery.Details[] httpSeeds = params.getHttpSeeds();
          if (httpSeeds != null) {
              OkHttpClient httpClient = new OkHttpClient();
              for (HttpDiscovery.Details httpSeed : httpSeeds)
                  discoveries.add(new HttpDiscovery(params, httpSeed, httpClient));
          }
          // Also use DNS seeds if there is no specific service requirement
          if (services == 0) {
              String[] dnsSeeds = params.getDnsSeeds();
              if (dnsSeeds != null)
                  for (String dnsSeed : dnsSeeds)
                      discoveries.add(new DnsSeedDiscovery(params, dnsSeed));
          }
          return new MultiplexingDiscovery(params, discoveries);
      }
  
      /**
       * Will query the given seeds in parallel before producing a merged response.
       */
      public MultiplexingDiscovery(NetworkParameters params, List<PeerDiscovery> seeds) {
          checkArgument(!seeds.isEmpty());
          this.netParams = params;
          this.seeds = seeds;
      }
  
      @Override
      public InetSocketAddress[] getPeers(final long services, final long timeoutValue, final TimeUnit timeoutUnit) throws PeerDiscoveryException {
          vThreadPool = createExecutor();
          try {
              List<Callable<InetSocketAddress[]>> tasks = Lists.newArrayList();
              for (final PeerDiscovery seed : seeds) {
                  tasks.add(new Callable<InetSocketAddress[]>() {
                      @Override
                      public InetSocketAddress[] call() throws Exception {
                          return seed.getPeers(services, timeoutValue,  timeoutUnit);
                      }
                  });
              }
              final List<Future<InetSocketAddress[]>> futures = vThreadPool.invokeAll(tasks, timeoutValue, timeoutUnit);
              ArrayList<InetSocketAddress> addrs = Lists.newArrayList();
              for (int i = 0; i < futures.size(); i++) {
                  Future<InetSocketAddress[]> future = futures.get(i);
                  if (future.isCancelled()) {
                      log.warn("Seed {}: timed out", seeds.get(i));
                      continue;  // Timed out.
                  }
                  final InetSocketAddress[] inetAddresses;
                  try {
                      inetAddresses = future.get();
                  } catch (ExecutionException e) {
                      log.warn("Seed {}: failed to look up: {}", seeds.get(i), e.getMessage());
                      continue;
                  }
                  Collections.addAll(addrs, inetAddresses);
              }
              if (addrs.size() == 0)
                  throw new PeerDiscoveryException("No peer discovery returned any results in "
                          + timeoutUnit.toMillis(timeoutValue) + "ms. Check internet connection?");
              Collections.shuffle(addrs);
              vThreadPool.shutdownNow();
              return addrs.toArray(new InetSocketAddress[addrs.size()]);
          } catch (InterruptedException e) {
              throw new PeerDiscoveryException(e);
          } finally {
              vThreadPool.shutdown();
          }
      }
  
      protected ExecutorService createExecutor() {
          return Executors.newFixedThreadPool(seeds.size(), new ContextPropagatingThreadFactory("Multiplexing discovery"));
      }
  
      @Override
      public void shutdown() {
          ExecutorService tp = vThreadPool;
          if (tp != null)
              tp.shutdown();
      }
  }