blob: f3f17166634181b4d79b0ee4317be16e42b65d64 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
package net.sourceforge.jnlp;
import java.util.concurrent.Callable;
/**
* A call that runs on a separate thread, with an optional timeout. It takes a runnable and allows
* joining.
*
* On join, throws any exceptions that occurred within the call, or a TimeOutException if
* it did not finish. Returns the value from the call.
*/
public class AsyncCall<T> {
static public class TimeOutException extends RuntimeException {
public TimeOutException() {
super("Call did not finish within the allocated time.");
}
}
private Thread handler;
private Callable<T> callable;
private long timeout;
private T callResult;
/* Captures exception from async call */
private Exception asyncException = null;
/* Create an AsyncCall with a given time-out */
public AsyncCall(Callable<T> callable, long timeout) {
this.callable = callable;
this.timeout = timeout;
this.handler = new HandlerThread();
}
/* Create an AsyncCall with (effectively) no time-out */
public AsyncCall(Callable<T> call) {
this(call, Long.MAX_VALUE);
}
/* Chains construction + start for convenience */
public static <T> AsyncCall<T> startWithTimeOut(Callable<T> callable, long timeout) {
AsyncCall<T> asyncCall = new AsyncCall<T>(callable, timeout);
asyncCall.start();
return asyncCall;
}
/* Chains construction + start for convenience */
public static <T> AsyncCall<T> startWithTimeOut(Callable<T> callable) {
return startWithTimeOut(callable, 1000); // Default timeout of 1 second
}
public void start() {
this.handler.start();
}
// Rethrows exceptions from handler thread, and throws TimeOutException in case of time-out.
public T join() throws Exception {
handler.join();
if (asyncException != null) {
throw asyncException;
}
return callResult;
}
/* The handler thread is responsible for timing-out the Callable thread.
* The resulting thread */
private class HandlerThread extends Thread {
@Override
public void run() {
Thread thread = new Thread() {
@Override
public void run() {
try {
/* Capture result of the call */
callResult = callable.call();
} catch (Exception e) {
/* In case of exception, capture for re-throw */
asyncException = e;
}
handler.interrupt(); // Finish early
}
};
thread.start();
try {
Thread.sleep(timeout);
} catch (InterruptedException e) {
// Finish early
return;
}
if (thread.isAlive()) {
asyncException = new TimeOutException();
}
// Make sure the thread is finished
while (thread.isAlive()) {
thread.interrupt();
}
}
}
}
|