Skip to content

Commit 4cd191c

Browse files
committed
Merge branch 'thread-queues'
This branch improves the thread service.
2 parents 96ae9be + ec4f6e0 commit 4cd191c

File tree

2 files changed

+69
-7
lines changed

2 files changed

+69
-7
lines changed

src/main/java/org/scijava/thread/DefaultThreadService.java

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333

3434
import java.awt.EventQueue;
3535
import java.lang.reflect.InvocationTargetException;
36+
import java.util.HashMap;
37+
import java.util.Map;
3638
import java.util.WeakHashMap;
3739
import java.util.concurrent.Callable;
3840
import java.util.concurrent.ExecutorService;
@@ -65,6 +67,9 @@ public final class DefaultThreadService extends AbstractService implements
6567

6668
private ExecutorService executor;
6769

70+
/** Mapping from ID to single-thread {@link ExecutorService} queue. */
71+
private Map<String, ExecutorService> queues;
72+
6873
private int nextThread = 0;
6974

7075
private boolean disposed;
@@ -117,6 +122,16 @@ public void queue(final Runnable code) {
117122
EventQueue.invokeLater(wrap(code));
118123
}
119124

125+
@Override
126+
public Future<?> queue(final String id, final Runnable code) {
127+
return executor(id).submit(wrap(code));
128+
}
129+
130+
@Override
131+
public <V> Future<V> queue(final String id, final Callable<V> code) {
132+
return executor(id).submit(wrap(code));
133+
}
134+
120135
@Override
121136
public Thread getParent(final Thread thread) {
122137
return parents.get(thread != null ? thread : Thread.currentThread());
@@ -141,9 +156,17 @@ public ThreadContext getThreadContext(final Thread thread) {
141156
// -- Disposable methods --
142157

143158
@Override
144-
public void dispose() {
159+
public synchronized void dispose() {
145160
disposed = true;
146-
if (executor != null) executor.shutdown();
161+
if (executor != null) {
162+
executor.shutdown();
163+
executor = null;
164+
}
165+
if (queues != null) {
166+
for (final ExecutorService queue : queues.values()) {
167+
queue.shutdown();
168+
}
169+
}
147170
}
148171

149172
// -- ThreadFactory methods --
@@ -157,12 +180,25 @@ public Thread newThread(final Runnable r) {
157180
// -- Helper methods --
158181

159182
private ExecutorService executor() {
160-
if (executor == null) {
161-
executor = Executors.newCachedThreadPool(this);
162-
}
183+
if (executor == null) initExecutor();
163184
return executor;
164185
}
165186

187+
private synchronized ExecutorService executor(final String id) {
188+
if (disposed) return null;
189+
if (queues == null) queues = new HashMap<>();
190+
if (!queues.containsKey(id)) {
191+
final ExecutorService queue = Executors.newSingleThreadExecutor();
192+
queues.put(id, queue);
193+
}
194+
return queues.get(id);
195+
}
196+
197+
private synchronized void initExecutor() {
198+
if (executor != null) return;
199+
executor = Executors.newCachedThreadPool(this);
200+
}
201+
166202
private Runnable wrap(final Runnable r) {
167203
final Thread parent = Thread.currentThread();
168204
return new Runnable() {

src/main/java/org/scijava/thread/ThreadService.java

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public enum ThreadContext {
112112

113113
/**
114114
* Gets whether the current thread is a dispatch thread for use with
115-
* {@link #invoke} and {@link #queue}.
115+
* {@link #invoke(Runnable)} and {@link #queue(Runnable)}.
116116
* <p>
117117
* In the case of AWT-based applications (e.g., Java on the desktop), this is
118118
* typically the AWT Event Dispatch Thread (EDT). However, ultimately the
@@ -141,7 +141,8 @@ void invoke(Runnable code) throws InterruptedException,
141141
InvocationTargetException;
142142

143143
/**
144-
* Queues the given code for later execution in a special dispatch thread.
144+
* Queues the given code for later execution in a special dispatch thread,
145+
* returning immediately.
145146
* <p>
146147
* In the case of AWT-based applications (e.g., Java on the desktop), this is
147148
* typically the AWT Event Dispatch Thread (EDT). However, ultimately the
@@ -152,6 +153,31 @@ void invoke(Runnable code) throws InterruptedException,
152153
*/
153154
void queue(Runnable code);
154155

156+
/**
157+
* Queues the given code for later execution in a dispatch thread associated
158+
* with the specified ID, returning immediately.
159+
*
160+
* @param id The ID designating which dispatch thread will execute the code.
161+
* @param code The code to execute.
162+
* @return A {@link Future} whose {@link Future#get()} method blocks until the
163+
* queued code has completed executing and returns {@code null}.
164+
* @see ExecutorService#submit(Runnable)
165+
*/
166+
Future<?> queue(String id, Runnable code);
167+
168+
/**
169+
* Queues the given code for later execution in a dispatch thread associated
170+
* with the specified ID, returning immediately.
171+
*
172+
* @param id The ID designating which dispatch thread will execute the code.
173+
* @param code The code to execute.
174+
* @return A {@link Future} whose {@link Future#get()} method blocks until the
175+
* queued code has completed executing and returns the result of the
176+
* execution.
177+
* @see ExecutorService#submit(Callable)
178+
*/
179+
<V> Future<V> queue(String id, Callable<V> code);
180+
155181
/**
156182
* Returns the thread that called the specified thread.
157183
* <p>

0 commit comments

Comments
 (0)