并行执行和终止多个线程

时间:2014-01-13 16:23:41

标签: java multithreading concurrency parallel-processing

我有一个简单的应用程序,我在一个类中创建3个线程来ping 3个不同的网站,并记下这样做的时间。

我希望通过查看3中哪个线程先成功执行并终止其他两个来增强它。

JDK的哪一类会有所帮助?怎么样?

ping网站的示例代码:

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;
}

2 个答案:

答案 0 :(得分:3)

  

我希望通过查看3中哪个线程先成功执行并终止其他两个来增强它。

我会将ExecutorServiceExecutorCompletionService结合使用。然后,当第一个任务完成时,从完成服务返回第一个Future时,您可以在shutdownNow()上调用ExecutorService

javadocs for ExecutorCompletionService非常好,并展示了如何使用它。

// 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

这种机制的唯一问题是这只会中断线程。在你的情况下,他们将陷入urlConn.connect();,这是不可中断的。在ecs.take()返回后,您将不得不重新运行任务,并在仍在进行中的disconnect()上致电HttpURLConnection。即便如此,我也不确定它是否会阻止目前​​正在进行的连接。如果这不起作用,那么您可能需要切换到使用Apache HttpClient或其他可以关闭的类来阻止线程等待更长时间。

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

在您的情况下,您的任务可能类似于:

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);
    }
}

以下是Java tutorial on ExecutorService及相关课程。

答案 1 :(得分:1)

我认为BlockingQueue可能有用。生成线程的主要思想在完成后会向BlockingQueue写入一些值,并在InterruptedException上正常关闭

例如:

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();
    }
}

请注意,没有处理InterruptedException。它应该添加到您的方法