使用InheritableThreadLocal<T>
精心制作的
@Override protected T childValue(T parentValue) {
// Use Thread.currentThread() -- the parent -- to make a return value.
}
使您无法控制的线程可以将对它们自己的引用传递给它们创建的任何子线程——这将是它们的子线程与父线程最接近的东西。
正如 Gray 所说,保留此类引用可能会阻碍 GC,因此WeakReference<Thread>
可能有必要将它们包装在 a 中。
这是一个每个线程都知道其完整祖先的示例,除非祖先已死并被 GC 掩埋。
import java.lang.ref.WeakReference;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.IntStream;
import static java.lang.Thread.currentThread;
public class ThreadAncestry {
/** Linked list holding the thread which created the current one, and its ancestry */
static class Chain {
final Chain ancestors;
final WeakReference<Thread> parent;
Chain(Chain ancestors, Thread parent) {
this.ancestors = ancestors;
this.parent = new WeakReference<>(parent);
}
@Override
public String toString() {
Thread parent = this.parent.get();
return (parent == null ? "[dead and buried]" : parent.getName())
+ (ancestors == null ? "" : " -> " + ancestors);
}
}
/** Prints the current thread's ancestry, then spawns a new thread which does the same. */
static void spawnRecursively(InheritableThreadLocal<Chain> ancestors, int remainingSpawns) {
System.out.println( "The ancestors of " + currentThread().getName() + " are " + ancestors.get());
if (remainingSpawns > 0)
new Thread(() -> spawnRecursively(ancestors, remainingSpawns - 1)).start();
}
/** Uses an InheritableThreadLocal to record the ancestry of each thread as they are created. */
public static void main(String[] args) {
InheritableThreadLocal<Chain> ancestors = new InheritableThreadLocal<Chain>() {
@Override
protected Chain childValue(Chain parentValue) {
return new Chain(parentValue, currentThread()); // This is called by the parent thread.
}
};
spawnRecursively(ancestors, 3);
IntStream.range(0, 6).parallel().forEach(
i -> System.out.println( i + " ran on " + currentThread().getName()
+ " with ancestors " + ancestors.get()));
ExecutorService service = Executors.newSingleThreadExecutor();
service.submit(() -> {
System.out.println( currentThread().getName() + " has ancestors "
+ ancestors.get() + "; it will now attempt to kill these.");
System.gc(); // May not work on all systems.
System.out.println( currentThread().getName() + " now has ancestors "
+ ancestors.get() + " after attempting to force GC.");
service.shutdown();
});
}
}
此示例在我的机器上产生以下输出:
The ancestors of main are null
The ancestors of Thread-0 are main
The ancestors of Thread-1 are Thread-0 -> main
The ancestors of Thread-2 are Thread-1 -> Thread-0 -> main
3 ran on main with ancestors null
4 ran on main with ancestors null
5 ran on ForkJoinPool.commonPool-worker-2 with ancestors main
0 ran on ForkJoinPool.commonPool-worker-3 with ancestors ForkJoinPool.commonPool-worker-1 -> main
1 ran on ForkJoinPool.commonPool-worker-1 with ancestors main
2 ran on ForkJoinPool.commonPool-worker-2 with ancestors main
pool-1-thread-1 has ancestors main; it will now attempt to kill these.
pool-1-thread-1 now has ancestors [dead and buried] after attempting to force GC.
我不确定这有多大用处,但它可以用于,例如,分层显示多个线程(您无法控制)中的每一个已打印System.out
或记录的内容java.util.Logger
;例如,这是您希望作为具有并行测试运行的测试框架的一部分来实现的东西。