java - ForkJoinPool,Phaser和托管阻塞:它们在多大程度上可以解决死锁?

这个小代码片段永远不会在jdk8u45上完成,并用于在jdk8u20上正确完成:

public class TestForkJoinPool {

    final static ExecutorService pool = Executors.newWorkStealingPool(8);
    private static volatile long consumedCPU = System.nanoTime();

    public static void main(String[] args) throws InterruptedException {
        final int numParties = 100;
        final Phaser p = new Phaser(1);
        final Runnable r = () -> {
            p.register();
            p.arriveAndAwaitAdvance();
            p.arriveAndDeregister();
        };

        for (int i = 0; i < numParties; ++i) {
            consumeCPU(1000000);
            pool.submit(r);
        }

        while (p.getArrivedParties() != numParties) {}
    }

    static void consumeCPU(long tokens) {
        // Taken from JMH blackhole
        long t = consumedCPU;
        for (long i = tokens; i > 0; i--) {
            t += (t * 0x5DEECE66DL + 0xBL + i) & (0xFFFFFFFFFFFFL);
        }
        if (t == 42) {
            consumedCPU += t;
        }
    }
}

doc of phaser表示
在forkjoinpool中执行的任务也可以使用phaser,这将确保在其他任务被阻塞等待一个阶段前进时有足够的并行性来执行任务。
但是javadoc of ForkjoinPool#mangedBlock表示:
如果在forkjoinpool中运行,则可以首先扩展池以确保足够的并行性
那里只有五月。所以我不确定这是否是一个bug,或者仅仅是一个不依赖phaser/forkjoinpool契约的错误代码:phaser/forkjoinpool组合的契约有多难防止死锁?
我的配置:
Linux ADC 3.14.27-100.fc19.x86 1 smp周三12月17日19:36:34 UTC 2014 x86_u 64 x86_u 64 GNU/Linux
8核i7

最佳答案

看起来您的问题来自jdk 8u20和8u45之间forkjoinpool代码的更改。
在u20中,forkjoin线程在被回收之前总是处于活动状态至少200毫秒(请参阅forkjoinpool.fast_idle_timeout)。
在u45中,一旦forkjoinpool达到了它的目标并行度加上2个额外的线程,线程将在没有等待的情况下一旦用完工作就死掉。
您可以在forkjoinpool.java中的awaitwork方法中看到此更改(第1810行):

    int t = (short)(c >>> TC_SHIFT);  // shrink excess spares
    if (t > 2 && U.compareAndSwapLong(this, CTL, c, prevctl))
        return false; 

你的程序使用相位器任务来创建额外的工人。每个任务都会产生一个新的补偿工作进程,该工作进程将拾取下一个提交的任务。
但是,一旦达到目标并行度+2,补偿工作进程将立即死亡而不等待,并且没有机会获取将在随后立即提交的任务。
我希望这能有帮助。

本文翻译自 https://stackoverflow.com/questions/30392753/

网站遵循 CC BY-SA 4.0 协议,转载或引用请注明出处。

标签 java java-8 phaser forkjoinpool


相关文章:

java - 仅从字符串标签中提取值

java - Android Studio重构还原所有lambdas和其他Java 8功能

java - 将线程注册到Phaser

java - 如何创建移相器的链/层

java - 移相器同步用法

java - Java:将外部恐怖代码转换为纯净API的最佳做法?

java - Ruby中的ActiveRecord模式是否像Ruby中那样实现? [关闭]

java - Java-对比较器感到困惑,需要使用一个(我认为)。内部更多信息

java - 如何在Java 8中生成给定长度的列表?

java - Java8对具有相同名称的数千个默认方法的接口进行了慢速编译