source: src/main/java/genius/core/session/ExecutorWithTimeout.java

Last change on this file was 167, checked in by Tim Baarslag, 6 years ago

Improved examples on how to use BOA components and how to combine them into a single party using BoaParty

File size: 4.2 KB
Line 
1package genius.core.session;
2
3import java.util.concurrent.ArrayBlockingQueue;
4import java.util.concurrent.BlockingQueue;
5import java.util.concurrent.Callable;
6import java.util.concurrent.ExecutionException;
7import java.util.concurrent.TimeUnit;
8import java.util.concurrent.TimeoutException;
9
10/**
11 * execute commands within the set timout limits. Compute and keeps remaining
12 * time for further calls. This executor can be called multiple times with
13 * different {@link Callable}s so that the total accumulated time will stay
14 * within the total timeoutms that is given in the constructor.
15 *
16 * This executor will run a separate timer and kill the {@link Callable} with
17 * thread.stop() to make a pretty hard kill attempt if the time runs out.
18 *
19 * @author W.Pasman, David Festen 1apr15
20 *
21 */
22public class ExecutorWithTimeout {
23
24 private long remainingTimeMs;
25
26 /**
27 * Construct an executor with a total available amount of time.
28 *
29 * @param timeoutms
30 * the total available time that this executor can spend.
31 */
32 public ExecutorWithTimeout(long timeoutms) {
33 remainingTimeMs = timeoutms;
34 }
35
36 /**
37 * Execute the command within the remaining time of this executor. Blocking
38 * call. Used time will be subtracted from the quotum of this Executor. This
39 * function is synchronized and can execute only 1 Callable at any time.
40 *
41 * @param name
42 * the name of the thread/process/agent for which we are
43 * executing. Used for error reporting.
44 * @param command
45 * the {@link Callable} to execute
46 * @return the result V
47 * @throws ExecutionException
48 * if the {@link Callable} threw an exception. The
49 * {@link ExecutionException} will contain the exception from
50 * the {@link Callable}.
51 * @throws TimeoutException
52 * if the {@link Callable} did not finish in time.
53 */
54 public synchronized <V> V execute(String name, final Callable<V> command)
55 throws ExecutionException, TimeoutException {
56
57 return new myThread<V>(command).executeWithTimeout(name, remainingTimeMs);
58 }
59}
60
61/**
62 * Private thread class, this is the thread where the Callable will be run.
63 *
64 * @author W.Pasman 1apr15
65 *
66 * @param <V>
67 * the return type of the callable.
68 */
69class myThread<V> extends Thread {
70 // flag indicating that the thread is done.
71 BlockingQueue<Boolean> ready = new ArrayBlockingQueue<Boolean>(1);
72
73 private V result = null;
74 private Throwable resultError = null;
75
76 Callable<V> callable;
77
78 public myThread(Callable<V> c) {
79 callable = c;
80 }
81
82 @Override
83 public void run() {
84 try {
85 result = callable.call();
86 } catch (Throwable e) { // you get here when an agent throws an exception
87 resultError = e;
88 e.printStackTrace();
89 }
90 try {
91 ready.put(true);
92 } catch (InterruptedException e) {
93 // at this point, either result or resultError has been set
94 // already.
95 }
96 }
97
98 /**
99 * Execute this thread and wait for thread to terminate or terminate after
100 * timeout millis. Blocking call. After return, the Callable has been
101 * executed, OR we have thrown.
102 *
103 * @param name
104 * the name for the thread (usually, the agent name). Used for
105 * reporting errors.
106 *
107 * @param timeout
108 * timeout in millis.
109 * @throws TimeoutException
110 * if the callable did not complete within the available time.
111 */
112 public V executeWithTimeout(String name, long timeout) throws ExecutionException, TimeoutException {
113 start();
114
115 // wait for the thread to finish, but at most timeout ms.
116 try {
117 if (ready.poll(timeout, TimeUnit.MILLISECONDS) == null) {
118 /*
119 * not finished. terminate and throw. stop() is only way to
120 * force thread to die. interrupt() is too weak. executorService
121 * only supports interrupt(), not stop(). Therefore we use plain
122 * Threads here.
123 */
124 stop();
125 throw new TimeoutException("agent " + name + " passed deadline and was killed");
126 }
127 } catch (InterruptedException e) {
128 /*
129 * we should not get here. Just in case
130 */
131 resultError = e;
132 }
133 // if we get here, thread ended and result or resultError was set.
134 if (resultError != null) {
135 throw new ExecutionException("Execution failed of " + name + ":" + resultError, resultError);
136 }
137 return result;
138 }
139}
Note: See TracBrowser for help on using the repository browser.