简体   繁体   中英

Parallel execution and termination of multiple threads

I have a simple application in which I create 3 threads inside a class to ping 3 different websites and note the time taken to do so.

I wish to enhance it by seeing which thread out of the 3 executes successfully first and terminating the other two .

Which class of the JDK would be helpful in doing so ? and how ?

Sample code to ping websites :

public static boolean pingUrl(final String address) {

 try {

  final URL url = new URL("http://" + address);

  final HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
  urlConn.setConnectTimeout(1000 * 10); // mTimeout is in seconds

  final long startTime = System.currentTimeMillis();

  urlConn.connect();

  final long endTime = System.currentTimeMillis();

  if (urlConn.getResponseCode() == HttpURLConnection.HTTP_OK) {

   System.out.println("Time (ms) : " + (endTime - startTime));
   System.out.println("Ping to "+address +" was success");

   return true;
  }
 } catch (final MalformedURLException e1) {
  e1.printStackTrace();
 } catch (final IOException e) {
  e.printStackTrace();
 }
 return false;
}

I wish to enhance it by seeing which thread out of the 3 executes successfully first and terminating the other two .

I would use an ExecutorService combined with a ExecutorCompletionService . Then, when the first Future is returned from the completion service when the first task completes, you would call shutdownNow() on the ExecutorService .

The javadocs for ExecutorCompletionService are pretty good and show how to use it.

// maybe you want 10 threads working on your tasks
ExecutorService threadPool = Executors.newFixedThreadPool(10); 
CompletionService<Result> ecs
     = new ExecutorCompletionService<Result>(threadPool);
for (Callable<Result> task : tasks) {
    // submit your tasks to the completion service, they run in the thread-pool
    ecs.submit(task);
}
// once you get one result
Future<Result> future = ecs.take();
// kill the rest of the tasks
threadPool.shutdownNow();
Result result = future.get();
// probably will need to close the thread connections, see below
// maybe call threadPool.awaitShutdown(...) here to wait for the others to die

The only problem with this mechanism is that this will only interrupt the threads. In your case they are going to be stuck in urlConn.connect(); which is not interruptible. Once the ecs.take() returns, you are going to have to run back over your tasks and call disconnect() on the the HttpURLConnection that are still in progress. Even then I'm not sure if it will stop a connection that is currently underway. If that doesn't work then you may need to switch to using Apache HttpClient or some other class that you can close to stop the threads from waiting longer.

for (Callable<Result> task : tasks) {
   // you'll need to do something like this
   task.closeConnection();
}

In your case, your task might look something like:

public class MyPingTask implements Callable<Boolean> {
    private String address;
    public MyPingTask(String address) {
        this.address = address;
    }
    public Boolean call() throws Exception {
         // obviously the pingUrl code could go right here
         return pingUrl(address);
    }
}

Here is the Java tutorial on ExecutorService and related classes.

I suppose BlockingQueue may be useful. The main idea that spawned thread writes some value to BlockingQueue when finished and gracefully closes on InterruptedException

For example:

public void runPing(List<String> urls) {
    Collection<Thread> runningThreads = new ArrayList<>(urls.size());
    final BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(urls.size());
    for (int i = 0; i < 3; i++) {
        final String url = urls.get(i);
        Thread t = new Thread(new Runnable() {
            public void run() {
                pingUrl(url);
                queue.add(1);
            }
        });
        runningThreads.add(t);
    }
    try {
        queue.poll(1, TimeUnit.HOURS);
        interruptChilds(runningThreads);
    } catch (Exception e) {
        interruptChilds(runningThreads);
    }
}

private void interruptChilds(Collection<Thread> runningThreads) {
    for (Thread t : runningThreads) {
        t.interrupt();
    }
}

Please note that in there are no handling of InterruptedException . It should be added in your method

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