[英]RecursiveTask thread is not blocked by join()
我有以下代码:
public class Main {
public static void main(String[] args) {
ExecutorService executorService = Executors.newWorkStealingPool(1);
ForkJoinPool workStealingPool = (ForkJoinPool)executorService;
RecursiveRunnable recursiveRunnable = new RecursiveRunnable(5);
workStealingPool.invoke(recursiveRunnable);
}
}
public class RecursiveRunnable extends RecursiveTask<Integer> implements Runnable {
private final int n;
public RecursiveRunnable(int n) {
this.n = n;
}
@Override
@SneakyThrows
protected Integer compute() {
Thread thread = Thread.currentThread();
System.out.println("Thread started, threadId=" + thread.getId() + " n=" + n + " activeCount=" + Thread.activeCount());
if (n <= 1) {
return n;
}
RecursiveRunnable f1 = new RecursiveRunnable(n - 1);
f1.fork();
RecursiveRunnable f2 = new RecursiveRunnable(n - 2);
f2.fork();
int result = 0;
result = f2.get() + f1.get();
System.out.println("Thread finished, threadId=" + thread.getId() + " n=" + n + " activeCount=" + Thread.activeCount() + " result=" + result);
return result;
}
@Override
public void run() {
compute();
}
}
我希望代码不会在fork()语句中打开新线程,
因为并行度是 1 。
但是这段代码的输出是:
线程启动,threadId=11 n=5 activeCount=3
线程启动,threadId=11 n=3 activeCount=3
线程启动,threadId=11 n=1 activeCount=3
线程启动,threadId=11 n=2 activeCount=3
线程启动,threadId=11 n=0 activeCount=3
线程启动,threadId=11 n=1 activeCount=3
线程完成,threadId=11 n=2 activeCount=3 result=1
线程完成,threadId=11 n=3 activeCount=3 result=2
线程启动,threadId=11 n=4 activeCount=3
线程启动,threadId=11 n=2 activeCount=3
线程启动,threadId=11 n=0 activeCount=3
线程启动,threadId=11 n=1 activeCount=3
线程完成,threadId=11 n=2 activeCount=3 result=1
线程启动,threadId=11 n=3 activeCount=3
线程启动,threadId=11 n=1 activeCount=3
线程启动,threadId=11 n=2 activeCount=3
线程启动,threadId=11 n=0 activeCount=3
线程启动,threadId=11 n=1 activeCount=3
线程完成,threadId=11 n=2 activeCount=3 result=1
线程完成,threadId=11 n=3 activeCount=3 result=2
线程完成,threadId=11 n=4 activeCount=3 result=3
线程完成,threadId=11 n=5 activeCount=3 result=5
从输出打印来看,我们似乎同时有 12 个线程处于活动状态。
尽管并行度为 1 ,但如何打开新线程?
Fork-Join 池中的join()不同于经典的 Java 线程连接。
Java 线程中的join()用作屏障同步器以等待另一个线程完成,然后您加入它(在另一个线程完成之前您不能继续)。 常规线程中的连接会阻塞调用线程。
Fork-Join 池中的join()不会简单地阻塞调用线程,相反,工作线程用于帮助运行子任务。
当 workerThread 遇到join()时,它会处理任何其他任务,直到它注意到目标子任务已完成。
在这个子任务结果完成之前,workerThread 不会返回给调用者。
Fork-Join 池任务中的join()不是阻塞的,它持有当前任务,因此只有在 join() 创建的子任务完成后才能继续计算。
工作线程发现,任务被阻塞,直到子任务完成,所以它开始处理子任务。
ForkJoinTask 比 Java 线程更轻。 一个真正的 Java 线程有它自己的堆栈、寄存器和许多其他资源,这些资源允许它由操作系统内部的线程调度程序独立管理。
大量的 ForkJoinTask 可以运行在 Fork-Join-Pool 中数量少得多的 WorkerThreads 中。 每个 WorkerThread 都是一个 Java 线程对象,具有您期望从普通线程获得的所有装备。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.