3

s と Thread プールが行うことに近いと思われる問題がありExecutorますが、それを正確に適合させることはできません。基本的に、初期化に少し時間がかかり、プールしたいワーカーがあり、準備ができたら、それらを使用して作業を行います。Thread でこれを行う必要があります:

worker = buildExpensiveWorker();
worker.doWork(work1);
worker.doWork(work2);
worker.doWork(work3);
...

エグゼキューターは私にこれを行うことしか許可しませんが:

doWork(work1);
doWork(work2);
doWork(work3);
...

独自のスレッド プールを作成する必要がありますか? すでにうまくいっているものを書き直すのは恥ずべきことです。またはThreadLocal、ワーカーを保持し、Runnableの run() メソッド内からそれらを管理するために使用する必要がありますか?

4

1 に答える 1

5

Thread オブジェクトが使用可能になる前に実際に初期化することについて話している場合は、ThreadPoolExecutor.setThreadFactory を見てください。

http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html#setThreadFactory(java.util.concurrent.ThreadFactory )

カスタム Thread サブクラスの作成やカスタム初期化など、任意の方法でスレッドを作成する独自の実装を提供できます。

ただし、初期化にコストがかかる場合は、実際のスレッドをできるだけ長く維持するようにエグゼキューターを構成するようにしてください (つまり、キープアライブ時間をかなり長く設定し、すべてのスレッドをスピンアップするようにしてください)。すぐに必要であり、ヒットを前に受けます)。

編集:スレッドローカルを使用する(コメントに記載されているように):

public class ThreadData {
    public static final ThreadLocal<String> data = new ThreadLocal<String>();
}

public class InitializingThread extends Thread {
    public InitializingThread(Runnable r) {
        super(r);
    }

    public void run() {
        ThreadData.data.set("foo");
        super.run();
    }
}

public class InitializingThreadFactory implements ThreadFactory {
    public Thread newThread(Runnable r) {
        return new InitializingThread(r);
    }
}

ThreadPoolExecutor executor = ...;
executor.setThreadFactory(new InitializingThreadFactory());
executor.execute(...);

そして、Runnable で:

public void run() {
     String s = ThreadData.data.get();
}

また、このアプローチ (Thread.currentThread() を使用してキャストするのではなく) には、任意の Thread 実装 (デフォルトを含む)、またはスレッドなし (.run() を直接呼び出す) で実際に使用できるという利点があります。 ThreadLocal に値を設定した後のメソッド)。「ThreadLocal」を「InherableThreadLocal」に簡単に変更し、スレッド プールに何かを送信する前に一度設定することもできます。すべての子スレッドは、親スレッド (プールを作成したスレッド) から値を継承します。

特定のスレッドの「実行」メソッドは、スレッド プール内であっても 1 回しか実行されないことに注意することが重要です。これにより、初期化ルーチンがスレッドごとに行われることが保証されます。

于 2012-08-19T03:32:54.837 に答える