我有一个简单的应用程序,我在一个类中创建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;
}
答案 0 :(得分:3)
我希望通过查看3中哪个线程先成功执行并终止其他两个来增强它。
我会将ExecutorService
与ExecutorCompletionService
结合使用。然后,当第一个任务完成时,从完成服务返回第一个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
。它应该添加到您的方法