我写了下面的程序。基本上,我使用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);
}
}程序运行后,由于main thread (),TIMED_WAITING保持在TIMED_WAITING状态。在由executor管理的线程中,我让它读取一个空的阻塞队列,并且这个线程永远保持在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不是在启动这些线程吗,那么它们是如何在堆栈中出现的呢?
发布于 2020-05-22 10:12:41
当您启动一个新的Thread时,它将在一个全新的调用堆栈上执行其run方法。这是Thread中代码的入口点。它与名为start的线程完全解耦。“父”线程继续在自己的堆栈上独立运行自己的代码,如果这两个线程中的任何一个崩溃或完成,它不会影响另一个线程。
在线程的堆栈帧中唯一出现的东西是在run中调用的任何东西。您看不到是谁调用了run ( JVM做到了这一点)。当然,除非您将start与run混为一谈,并且直接从您自己的代码调用run。那么就根本不涉及新线程了。
在这里,线程不是由自己的代码直接创建的,而是由executor服务创建的。但是它没有做任何不同的事情,它还必须通过调用构造函数来创建线程并使用start启动它们。最终结果是一样的。
run通常所做的是委托给在其构造函数中设置的Runnable。您可以在这里看到: executor服务已经安装了一个ThreadPoolExecutor$Worker实例。这个包含在新线程上运行的所有代码,并控制它与执行器的交互。
然后,该ThreadPoolExecutor$Worker将调用其有效负载代码、应用程序代码、已提交给执行器的任务。在您的例子中,这是com.example.cs.executors.CSExecutorUnderstanding$$Lambda$2/1705736037。
https://stackoverflow.com/questions/61952435
复制相似问题