如何找到父线程的名称?

我知道当我们谈论流程时,我们可以拥有“父母”和“孩子”。 但是有可能获得父Thread名称吗?

我做了我的研究,但我只找到了.Net的答案


编辑:我尝试设置名称:

 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()); } } 

我知道当我们谈论流程时,我们可以拥有“父母”和“孩子”。 但是有可能获得父线程名称吗?

正如Jon所说,线程无法知道其父线程。 这很重要,因为如果每个子节点都引用了分叉它们的线程,那么这将意味着内存中存在许多不必要的线程结构。 GC无法回收父线程结构,或者如果子进程对其进行引用,则重用该父线程结构。

在查看代码时,父代用于获取守护程序状态,优先级和其他信息,但不存储在Thread对象中。

您提到您需要拥有线程的名称,以便您可以将那些“在控制流中一起”的组合在一起。 我会研究ThreadGroup的。 它们不经常使用,但在这种情况下你可能想要:

 ThreadGroup threadGroup = new ThreadGroup("mythreadgroup"); Thread thread = new Thread(threadGroup, new Runnable() {...}); ... // then you can do such methods as threadGroup.enumerate(...); 

使用线程组,您可以将多个线程绑定在一起。 当然,您也可以使用自己的系列来完成此操作。


编辑:

您提到真正的问题是如何衡量分布式系统的每个组件中的“花费的时间” – 在这种情况下是RMI处理程序。

我担心这里没有简单的答案。 对于挂钟,您将不得不将每个RMI方法调用开始时的System.currentTimeMillis()与结束时的时间进行比较。 您还可以使用以下代码来测试线程使用的CPU时间。

 ThreadInfo threadInfo = ManagementFactory.getThreadMXBean().getThreadCpuTime(thread.getId()); 

要获得“用户”时间,请使用getThreadUserTime(...) 。 我不确定线程​​ID是否被重用,所以你可能需要做的就是在集合中的RMI调用中记录所有线程ID,然后在监视线程中记录它们的CPU和用户时间。

我怀疑RMI线程有一个特定的名称,因此您的监视线程可以找到线程列表中的线程来执行此操作,但您无法确定哪个线程正在处理哪个RMI请求。

最后,要考虑的一件事是在过程中的多个点上采用时间戳,并在调用之间传递这个long[] 。 这会增加一小部分数据开销,但您可以很好地了解分布式系统各个不同部分的性能。

不 – 在Java或.NET中没有“父”线程的特定概念。 但是,根据您引用的.NET答案,如果您自己创建线程,则始终可以在新线程的名称中指定一个名称,指示“创建者”线程名称。

编辑:您的示例代码开始之前设置名称…但启动后将其覆盖,忽略以前的名称。

我希望有类似的东西:

 String currentName = Thread.currentThread.name(); Thread thread = new Thread(new RunnableC()); thread.setName("C (started by" + currentName + ")"); thread.start(); 

这将是线程名称设置的唯一位置。

请注意,这也使用了实现Runnable而不是扩展Thread的想法。 这是一个单独的问题,但在大多数情况下是首选方法。

使用InheritableThreadLocal精心设计

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

使你无法控制的线程可以将对自己的引用传递给他们创建的任何子线程 – 这将是他们的孩子与父母最接近的事情。

正如Gray所提到的,保持这样的引用可能会阻碍GC,因此将它们包装在WeakReference可能是必要的。

下面是一个例子,其中每个线程都知道它的完整祖先,除非祖先死亡并被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 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 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 ancestors = new InheritableThreadLocal() { @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记录java.util.Logger ; 例如,这是您希望作为具有并行测试运行的测试框架的一部分实现的。

在接受的答案中,Gray提到线程本地可能是从一个启动另一个线程的线程inheritance的(即父对子;请注意术语“父”和“子”在这里没有任何特殊的技术含义)。

基于这个想法,似乎有一种方法可以使用InheritableThreadLocal找出父线程:在父级中设置的任何值(如name )将自动在子级中可用。


此外,如果我们不控制子线程(例如我们在线程中运行第三方组件,并且它产生了一些我们希望跟踪的线程),也可以使用这种机制。 reflection可以让我们看到其他线程的线程本地 。

这可能允许我们例如拍摄所有正在运行的线程的快照,并找出由我们的线程启动的线程,以及这些线程的子项等 – 所有后代。 应该很好地用于监控目的。 不确定它是否对其他任何东西都有好处。