Reputation: 213
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;
}
Upvotes: 0
Views: 1027
Reputation: 116908
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.
Upvotes: 3
Reputation: 718
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
Upvotes: 1