1 | /* |
2 | * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, |
3 | * and the EPL 1.0 (http://h2database.com/html/license.html). |
4 | * Initial Developer: H2 Group |
5 | */ |
6 | package org.h2.util; |
7 | |
8 | import java.util.concurrent.atomic.AtomicInteger; |
9 | |
10 | /** |
11 | * A method call that is executed in a separate thread. If the method throws an |
12 | * exception, it is wrapped in a RuntimeException. |
13 | */ |
14 | public abstract class Task implements Runnable { |
15 | |
16 | private static AtomicInteger counter = new AtomicInteger(); |
17 | |
18 | /** |
19 | * A flag indicating the get() method has been called. |
20 | */ |
21 | public volatile boolean stop; |
22 | |
23 | /** |
24 | * The result, if any. |
25 | */ |
26 | protected Object result; |
27 | |
28 | private volatile boolean finished; |
29 | |
30 | private Thread thread; |
31 | |
32 | private Exception ex; |
33 | |
34 | /** |
35 | * The method to be implemented. |
36 | * |
37 | * @throws Exception any exception is wrapped in a RuntimeException |
38 | */ |
39 | public abstract void call() throws Exception; |
40 | |
41 | @Override |
42 | public void run() { |
43 | try { |
44 | call(); |
45 | } catch (Exception e) { |
46 | this.ex = e; |
47 | } |
48 | finished = true; |
49 | } |
50 | |
51 | /** |
52 | * Start the thread. |
53 | * |
54 | * @return this |
55 | */ |
56 | public Task execute() { |
57 | return execute(getClass().getName() + ":" + counter.getAndIncrement()); |
58 | } |
59 | |
60 | /** |
61 | * Start the thread. |
62 | * |
63 | * @param threadName the name of the thread |
64 | * @return this |
65 | */ |
66 | public Task execute(String threadName) { |
67 | thread = new Thread(this, threadName); |
68 | thread.setDaemon(true); |
69 | thread.start(); |
70 | return this; |
71 | } |
72 | |
73 | /** |
74 | * Calling this method will set the stop flag and wait until the thread is |
75 | * stopped. |
76 | * |
77 | * @return the result, or null |
78 | * @throws RuntimeException if an exception in the method call occurs |
79 | */ |
80 | public Object get() { |
81 | Exception e = getException(); |
82 | if (e != null) { |
83 | throw new RuntimeException(e); |
84 | } |
85 | return result; |
86 | } |
87 | |
88 | /** |
89 | * Whether the call method has returned (with or without exception). |
90 | * |
91 | * @return true if yes |
92 | */ |
93 | public boolean isFinished() { |
94 | return finished; |
95 | } |
96 | |
97 | /** |
98 | * Get the exception that was thrown in the call (if any). |
99 | * |
100 | * @return the exception or null |
101 | */ |
102 | public Exception getException() { |
103 | stop = true; |
104 | if (thread == null) { |
105 | throw new IllegalStateException("Thread not started"); |
106 | } |
107 | try { |
108 | thread.join(); |
109 | } catch (InterruptedException e) { |
110 | // ignore |
111 | } |
112 | if (ex != null) { |
113 | return ex; |
114 | } |
115 | return null; |
116 | } |
117 | |
118 | } |