StreamパラレルストリームのBugを1回記録

1865 ワード

この間、奇妙な問題に遭遇し、問題が発生した現場をシミュレートしました.
public class StreamTest {

    static {
        int sum = IntStream.range(0, 100)
                .parallel()
                .map(i -> i)
                .sum();
        System.out.println("sum = " + sum);
    }

    public static void main(String[] args) {
    }

}

上記のコードは実行時にデッドロックが発生し,コードは静的コードブロックの出力を実行せず,つまりStream計算という場所にブロックされる.Streamを通常のシリアル・ストリームに変更すると、コードは正常に動作します.では、問題は並列に現れます.
Streamの並列動作はForkJoinPoolによって実現され、ForkJoinPoolは特殊なスレッドプールであり、タスクを分割計算することによって、結果を統合してcpuマルチコア性能を十分に利用する特殊なスレッドプールである.Streamに最も穴があるのは、すべての並列操作が同じForkJoinPoolプール、つまりForkJoinPoolを使用していることです.commPool()が返すこのプールは、次のコードで検証できます.
public static void main(String[] args) {
        IntStream.range(0,10).parallel().forEach(i-> System.out.println(Thread.currentThread().getName()));
    }

したがって,この問題が発生する鍵はStreamではなく,マルチスレッドとクラス初期化にある.私がテストした結果、以下のコードは依然として同じ問題を発生します.
public class StreamTest {
    static {
        Thread thread = new Thread(() -> {
            try {
                Thread.sleep(500);
                System.out.println("StreamTest.static initializer");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        thread.start();
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
    }

}

クラスが初期化を完了していない場合、静的コードブロックの他のスレッド操作は現在のクラスの初期化が完了するのを待つが、現在のクラスの初期化は他のスレッド操作の完了を待つため、デッドロックが発生することが確認された.
私の提案は静的コードブロックの中でいかなるスレッド関連の操作をしないで、私の後続の検索を経て、Stack Overflowの上で1つの同じ問題の解答を発見して、完璧にこの問題が現れた原因を説明しました:
https://stackoverflow.com/questions/34820066/why-does-parallel-stream-with-lambda-in-static-initializer-cause-a-deadlock