Skip to content

Commit 035e58d

Browse files
committed
ThreadService: introduce the getParent(Thread) method
Due to the use of a thread pool, it is impossible to determine which thread called the current one. Sometimes we need that, though, e.g. when ImageJ 1.x wants to determine the (thread-local) macro options and runs in a thread that was spawned through the thread service. So let's add API to determine the parent thread, so that the ImageJ 1.x patcher can be extended to support macro options even when the ThreadService is involved. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
1 parent df69ca7 commit 035e58d

File tree

2 files changed

+55
-4
lines changed

2 files changed

+55
-4
lines changed

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

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
import java.awt.EventQueue;
3535
import java.lang.reflect.InvocationTargetException;
36+
import java.util.WeakHashMap;
3637
import java.util.concurrent.Callable;
3738
import java.util.concurrent.ExecutorService;
3839
import java.util.concurrent.Executors;
@@ -63,18 +64,20 @@ public final class DefaultThreadService extends AbstractService implements
6364

6465
private boolean disposed;
6566

67+
private WeakHashMap<Thread, Thread> parents = new WeakHashMap<Thread, Thread>();
68+
6669
// -- ThreadService methods --
6770

6871
@Override
6972
public <V> Future<V> run(final Callable<V> code) {
7073
if (disposed) return null;
71-
return executor().submit(code);
74+
return executor().submit(wrap(code));
7275
}
7376

7477
@Override
7578
public Future<?> run(final Runnable code) {
7679
if (disposed) return null;
77-
return executor().submit(code);
80+
return executor().submit(wrap(code));
7881
}
7982

8083
@Override
@@ -92,13 +95,18 @@ public void invoke(final Runnable code) throws InterruptedException,
9295
}
9396
else {
9497
// invoke on the EDT
95-
EventQueue.invokeAndWait(code);
98+
EventQueue.invokeAndWait(wrap(code));
9699
}
97100
}
98101

99102
@Override
100103
public void queue(final Runnable code) {
101-
EventQueue.invokeLater(code);
104+
EventQueue.invokeLater(wrap(code));
105+
}
106+
107+
@Override
108+
public Thread getParent(final Thread thread) {
109+
return parents.get(thread != null ? thread : Thread.currentThread());
102110
}
103111

104112
// -- Disposable methods --
@@ -128,4 +136,37 @@ private ExecutorService executor() {
128136
return executor;
129137
}
130138

139+
private Runnable wrap(final Runnable r) {
140+
final Thread parent = Thread.currentThread();
141+
return new Runnable() {
142+
@Override
143+
public void run() {
144+
final Thread thread = Thread.currentThread();
145+
try {
146+
if (parent != thread) parents.put(thread, parent);
147+
r.run();
148+
}
149+
finally {
150+
if (parent != thread) parents.remove(thread);
151+
}
152+
}
153+
};
154+
}
155+
156+
private <V> Callable<V> wrap(final Callable<V> c) {
157+
final Thread parent = Thread.currentThread();
158+
return new Callable<V>() {
159+
@Override
160+
public V call() throws Exception {
161+
final Thread thread = Thread.currentThread();
162+
try {
163+
if (parent != thread) parents.put(thread, parent);
164+
return c.call();
165+
}
166+
finally {
167+
if (parent != thread) parents.remove(thread);
168+
}
169+
}
170+
};
171+
}
131172
}

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,14 @@ void invoke(final Runnable code) throws InterruptedException,
113113
*/
114114
void queue(final Runnable code);
115115

116+
/**
117+
* Returns the thread that called the specified thread.
118+
* <p>
119+
* This works only on threads which the thread service knows about, of course.
120+
* </p>
121+
*
122+
* @param thread the managed thread, null refers to the current thread
123+
* @return the thread that asked the {@link ThreadService} to spawn the specified thread
124+
*/
125+
Thread getParent(final Thread thread);
116126
}

0 commit comments

Comments
 (0)