由执行器框架管理的线程的线程转储

Thread dump for threads which are managed by executor framework

我写了下面的程序。基本上我使用 executor framework 来管理线程。我还使用了 BlockingQueue 并故意将其保持为空,以便线程保持等待状态。

程序如下:


package com.example.executors;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

public class ExecutorDemo {

    public static void main(String[] args) throws InterruptedException {

        ScheduledExecutorService scheduledThreadPool = null;
        BlockingQueue<Integer> bq = new LinkedBlockingQueue<>();

        scheduledThreadPool = Executors.newSingleThreadScheduledExecutor((Runnable run) -> {
            Thread t = Executors.defaultThreadFactory().newThread(run);
            t.setDaemon(true);
            t.setName("Worker-pool-" + Thread.currentThread().getName());
            t.setUncaughtExceptionHandler(
                    (thread, e) -> System.out.println("thread is --> " + thread + "exception is --> " + e));
            return t;
        });

        ScheduledFuture<?> f = scheduledThreadPool.scheduleAtFixedRate(() -> {
            System.out.println("Inside thread.. working");
            try {
                bq.take();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }, 2000, 30000, TimeUnit.MILLISECONDS);

        System.out.println("f.isDone() ---> " + f.isDone());
        Thread.sleep(100000000000L);
    }
}

程序运行后,由于 Thread.sleep(),main thread 保持在 TIMED_WAITING 状态。在由执行程序管理的线程中,我正在让它读取一个空的阻塞队列,并且该线程永远保持 WAITING 状态。我想看看 thread dump 在这种情况下看起来如何。我在下面捕获了它:

"Worker-pool-main" #10 daemon prio=5 os_prio=31 tid=0x00007f7ef393d800 nid=0x5503 waiting on condition [0x000070000a3d8000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000007955f7110> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
        at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
        at com.example.cs.executors.CSExecutorUnderstanding.lambda(CSExecutorUnderstanding.java:34)
        at com.example.cs.executors.CSExecutorUnderstanding$$Lambda/1705736037.run(Unknown Source)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access1(ScheduledThreadPoolExecutor.java:180)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

正如预期的那样,线程 Worker-pool-main 保持在 WAITING 状态。我的疑问是 thread dump.

由于 executor service 管理 executor framework 中线程的生命周期,那么此线程转储如何从 Thread.run() 方法开始。

不应该是先出现executor的一部分然后Thread.run()

基本上,疑问是:当生命周期由 executor 管理时,那么为什么 Thread.run() 会首先出现并在堆栈上部看到 executors 的部分。 executors 不是在启动这些线程吗,那么它们是如何出现在堆栈中的?

当您启动一个新的 Thread 时,它将在一个全新的调用堆栈上执行其 run 方法。那是 Thread 中代码的入口点。它与调用 start 的线程完全分离。 "parent" 线程继续 运行 独立地在自己的堆栈上编写自己的代码,如果两个线程中的任何一个崩溃或完成,它都不会影响另一个。

线程堆栈帧中唯一显示的是在 run 中调用的内容。您看不到谁调用了 run(JVM 做到了)。当然,除非您将 startrun 混淆并直接从您自己的代码中调用了 run。然后根本就没有涉及新的线程。

这里线程不是自己代码直接创建的,而是executor服务创建的。但是那个没有做任何不同,它也必须通过调用构造函数创建线程并使用 start 启动它们。最终结果是一样的。

run 通常做的是委托给已在其构造函数中设置的 Runnable。您会在此处看到:执行程序服务已安装 ThreadPoolExecutor$Worker 实例。这个包含所有代码 运行 在新线程上并控制它与执行程序的交互。

然后 ThreadPoolExecutor$Worker 将依次调用其有效负载代码、您的应用程序代码以及已提交给执行程序的任务。在您的情况下,即 com.example.cs.executors.CSExecutorUnderstanding$$Lambda/1705736037.