3

次の小さなコード スニペットは、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;
        }
    }
}

フェイザーのドキュメントには、次のように記載されています

Phaser は、ForkJoinPool で実行されているタスクでも使用できます。これにより、フェーズが進むのを待っている他のタスクがブロックされている場合に、タスクを実行するのに十分な並列性が保証されます。

ただし、ForkjoinPool#mangedBlock の javadoc には次のように記載されています。

ForkJoinPool で実行している場合は、最初にプールを拡張して、十分な並列性を確保することができます

そこにあるのは5月だけです。したがって、これがバグなのか、それとも Phaser/ForkJoinPool のコントラクトに依存していない単に悪いコードなのかはわかりません。Phaser/ForkJoinPool の組み合わせのコントラクトは、デッドロックを防ぐためにどの程度機能しますか?


私の設定:

  1. 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
  2. 8 コア i7
4

1 に答える 1

1

あなたの問題は、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; 

プログラムは Phasers タスクを使用して追加のワーカーを作成します。各タスクは、次に送信されたタスクを取得するための新しい補正ワーカーを生成します。
ただし、目標の並列度 + 2 に達すると、補償ワーカーは待機せずにすぐに死亡し、その後すぐに投入されるタスクを拾う機会がありません。

これが役立つことを願っています。

于 2015-06-02T16:09:45.683 に答える