How to find the name of the parent thread?

Viewed 24838

I know we can have 'parents' and 'children' when we are talking about processes. But is it possible to get parent Thread name?

I did my research, but I have found answer only for .Net


Edit: I tried setting names:

public class Main {

    public static void main(String[] args) {
        Thread r = new ThreadA();
        r.start();
    }

}



public class ThreadA extends Thread {
    public void run() {
        Thread.currentThread().setName("Thread A");
        System.out.println("Here  " + Thread.currentThread().getName());
        Thread r = new ThreadB();
        r.setName(Thread.currentThread().getName());
        r.start();
    }
}

public class ThreadB extends Thread {
    public void run() {
        Thread.currentThread().setName("Thread B");
        System.out.println("Here " + Thread.currentThread().getName());
        Thread r = new ThreadC();
        r.setName(Thread.currentThread().getName());
        r.start();
    }
}

public class ThreadC extends Thread {
    public void run() {
        Thread.currentThread().setName("Thread C");
        System.out.println("Here " + Thread.currentThread().getName());
    }
}
4 Answers

Using InheritableThreadLocal<T> with a carefully crafted

@Override protected T childValue(T parentValue) {
    // Use Thread.currentThread() -- the parent -- to make a return value.
}

makes it possible for threads you have no control over to pass a reference to themselves to any child threads they create -- this will be the closest thing their children have to a parent.

As mentioned by Gray, keeping such references could hinder GC, so wrapping them in a WeakReference<Thread> could be necessary.

Here is an example where each thread knows its full ancestry, unless ancestors are dead and buried by 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();
        });
    }

}

This example results in the following output on my machine:

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.

I'm not sure how generally useful this is, but it can be used to, e.g., hierarchically display what each of a number of threads (over which you have no control) have printed to System.out or logged with java.util.Logger; this is something you would want to implement as part of a test framework with parallel test runs, for instance.

Related