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

原文 标签 java java-8 phaser forkjoinpool

这个小代码段永远不会在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中执行的任务也可以使用相位器,当其他任务被阻止等待阶段前进时,它将确保足够的并行度来执行任务。

但是javadoc of ForkjoinPool#mangedBlock指出:

如果在ForkJoinPool中运行,则可能首先扩展池以确保足够的并行度

那里只有一个。因此,我不确定这是错误还是不依赖Phaser / ForkJoinPool合同的错误代码:Phaser / ForkJoinPool组合的合同在防止死锁方面有多努力?

我的配置:
  • Linux adc 3.14.27-100.fc19.x86_64#1 SMP Wed Dec 17 19:36:34 UTC 2014 x86_64 x86_64 x86_64 GNU / Linux
  • 8核i7
  • 最佳答案

    看来您的问题来自JDK 8u20和8u45之间的ForkJoinPool代码更改。

    在u20中,ForkJoin线程在回收之前始终至少存活200毫秒(请参阅ForkJoinPool.FAST_IDLE_TIMEOUT)。

    在u45中,一旦ForkJoinPool达到了其目标并行度加上2个额外的线程,线程将在没有工作的情况下立即耗尽而无需等待。
    您可以在ForkJoinPool.java(第1810行)的awaitWork方法中看到此更改:

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

    您的程序使用Phasers任务来创建额外的工作程序。每个任务都会产生一个新的补偿工作程序,该工作程序负责接听下一个提交的任务。
    但是,一旦达到目标并行度+ 2,补偿工作人员将立即死亡,而无需等待,并且没有机会承担随后将立即提交的任务。

    我希望这有帮助。

    相关文章:

    java - 具有基本类型的XSD元素

    java - 任务栏位置或大小更改时如何移动JFrame? [重复]

    oracle - JodaTime或Java 8是否具有对JD Edwards日期和时间的特殊支持?

    java - 如何正确使用Phaser?

    java - 活动的某些部分如何存储在Android的外部类中?

    java - 如果单击外部可见的JPopupMenu,则强制选择JTable行

    performance - Java-重复的函数调用减少了执行时间

    java-8 - 我可以在IBM的Bluemix应用程序平台上使用Java 8吗?

    javascript - 相位器3:为什么没有图像显示?