简体   繁体   中英

a funny thing happens… ExecutorCompletionService

I have an application written in java that needs to find all the reachable hosts on the network.

I use InetAddress.isReachable() to do this with a timeout of 2000 milliseconds.

I look up the current local machine's IP address and based on that I attempt to reach the other IP addresses that end 1 - 255 missing out the local machines IP address.

It all works fine single threaded, just takes a long time as most of the IP addresses are not reachable as they do not exist so use up the 2 second timeout.

To speed things up (and try out concurrency in action :: Brian Goetz) i tried using Future and Callable etc.

This all went fine as well.

However i fancied using ExecutorCompletionService to give my users a more responsive application, so they could see results as they came available using

Future<Reach> reachedFuture = completionService.take();

Running this on a singleprocessor machine with the following config causes only 1 of the four reachable hosts to be identified:

private static final int poolSize = 10;
private static final int maxPoolSize = 10;
private static final long keepAliveTime = 120;

private static final LinkedBlockingQueue<Runnable> queue
        = new LinkedBlockingQueue<Runnable>(20);

private static final ExecutorService executorService
        = new ThreadPoolExecutor(poolSize, maxPoolSize, keepAliveTime, TimeUnit.SECONDS, queue);

private static final CompletionService<Reach> completionService
        = new ExecutorCompletionService<Reach>(executorService);

Changing it to this on a quad core machine also made it fail to detect all the reachable hosts:

private static final int poolSize
        = Math.max(2,Runtime.getRuntime().availableProcessors());

private static final int maxPoolSize
        = Math.max(2,Runtime.getRuntime().availableProcessors());

By changing the InetAddress.isReachable() timeout to 10 seconds made the last config work ok.

Also by changing the config as follows on the quad core machine also made it work with a 2 second timeout:

private static final int poolSize = 2;
private static final int maxPoolSize = 2;

Am I missing something very obvious why this happens?

What stops InetAddress.isReachable(2000) from detecting all the reachable hosts on my network?

Why does attempting to run multiple InetAddress.isReachable() calls fail?

So I wrote a little test script on my Mac and I can't get it to fail -- regardless of the size of the pool. I did change the LinkedBlockingQueue to be unlimited otherwise I couldn't submit all of the jobs. Also, after a while the isReachable() method was throwing a ConnectException so I had to handle that specifically. Is this the problem with your code @user423199?

Here's the code:

http://pastie.org/2460991

I'm wondering what OS you are running this on? Certain IP stacks may not like multiple threads doing ICMP packets within the same process. I would have thought that all modern operating systems would be smart about that but this may be a potential issue. It also may be some bug between the Java JRE and the OS stack.

Hope this helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM