我已经编写了以下程序。基本上,我使用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$2(CSExecutorUnderstanding.java:34)
at com.example.cs.executors.CSExecutorUnderstanding$$Lambda$2/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.access$301(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
的线程完全分离。 “父”线程继续在其自己的堆栈上独立运行其自己的代码,并且如果两个线程中的任何一个崩溃或完成,都不会影响另一个线程。
唯一出现在线程的堆栈帧中的是run
内部被调用的内容。您不会看到谁调用了run
(JVM做到了)。当然,除非您将start
与run
混淆,然后直接从您自己的代码中调用run
。这样就根本不涉及任何新线程。
这里,线程不是由您自己的代码直接创建的,而是由执行程序服务创建的。但这并没有什么不同,它还必须通过调用构造函数来创建线程,并使用start
启动它们。最终结果是相同的。
run
通常所做的是委派给已在其构造函数中设置的Runnable
。您将在此处看到以下内容:执行程序服务已安装ThreadPoolExecutor$Worker
实例。此代码包含要在新线程上运行并控制其与执行程序的交互的所有代码。
然后,ThreadPoolExecutor$Worker
随后将调用其有效负载代码,您的应用程序代码,已提交给执行者的任务。您的情况是com.example.cs.executors.CSExecutorUnderstanding$$Lambda$2/1705736037
。