7

ForkJoinPool1つの実行スレッドを使用するように構成することはできますか?

Random内で呼び出すコードを実行していますForkJoinPool。実行するたびに実行時の動作が異なり、リグレッションの調査が難しくなります。

コードベースが「デバッグ」モードと「リリース」モードを提供することを望みます。「デバッグ」モードはRandom、固定シードとForkJoinPool単一の実行スレッドで構成されます。「リリース」モードでは、システム提供Randomのシードが使用され、デフォルトのForkJoinPoolスレッド数が使用されます。

ForkJoinPool並列度 1 で構成しようとしましたが、2 つmainのスレッド (および 2 つ目のワーカー スレッド) を使用します。何か案は?

4

2 に答える 2

8

それで、私が間違っていたことがわかりました。

を 1 に設定して構成するForkJoinPoolparallelism、1 つのスレッドのみがタスクを実行します。mainスレッドは でブロックされていますForkJoin.get()。実際にはタスクを実行しません。

とはいえ、決定論的な動作を提供するのは本当に難しいことがわかりました。ここに私が修正しなければならなかったいくつかの問題があります:

  • ForkJoinPoolワーカースレッドが十分長くアイドル状態になった場合、別のワーカースレッド (別の名前) を使用してタスクを実行していました。たとえば、メイン スレッドがデバッグ ブレークポイントで中断された場合、ワーカー スレッドはアイドル状態になり、シャットダウンされます。実行を再開するForkJoinThreadと、別の名前の新しいワーカー スレッドがスピンアップします。これを解決するために、既に稼働中のワーカーがある場合に返すカスタム実装を提供する必要ForkJoinWorkerThreadFactorynullForkJoinPoolがありました(これにより、プールが複数のワーカーを作成するのを防ぎます)。Randomまた、ワーカー スレッドがシャットダウンして再び戻ってきた場合でも、コードが同じインスタンスを返すようにしました。
  • HashMapまたはHashSet実行ごとに異なる順序で乱数を取得する要素につながるなど、非決定論的な反復順序を持つコレクション。LinkedHashMapと を使用してこれを修正しましたLinkedHashSet
  • などの非決定論的 hashCode() 実装を持つオブジェクトEnum.hashCode()。これがどのような問題を引き起こしたかは忘れましたが、組み込みメソッドに頼るのではなく、自分で hashCode() を計算して修正しました。

ForkJoinWorkerThreadFactory の実装例を次に示します。

class MyForkJoinWorkerThread extends ForkJoinWorkerThread
{
    MyForkJoinWorkerThread(ForkJoinPool pool)
    {
        super(pool);
        // Change thread name after ForkJoinPool.registerWorker() does the same
        setName("DETERMINISTIC_WORKER");
    }
}

ForkJoinWorkerThreadFactory factory = new ForkJoinWorkerThreadFactory()
{
    private WeakReference<Thread> currentWorker = new WeakReference<>(null);

    @Override
    public synchronized ForkJoinWorkerThread newThread(ForkJoinPool pool)
    {
        // If the pool already has a live thread, wait for it to shut down.
        Thread thread = currentWorker.get();
        if (thread != null && thread.isAlive())
        {
            try
            {
                thread.join();
            }
            catch (InterruptedException e)
            {
                log.error("", e);
            }
        }
        ForkJoinWorkerThread result = new MyForkJoinWorkerThread(pool);
        currentWorker = new WeakReference<>(result);
        return result;
    }
};
于 2016-01-14T15:32:11.273 に答える
1

メイン スレッドは常に、アプリケーションが作成する最初のスレッドです。したがって、ForkJoinPoolwithparallelismを作成すると1、別のスレッドが作成されます。事実上、アプリケーションには 2 つのスレッドが存在します (複数poolのスレッドを作成したため)。

メインのスレッドが 1 つだけ必要な場合は、コードを順番に (並列ではなく) 実行できます。

于 2015-12-01T05:16:32.230 に答える