1

スレッドプール経由で実行したいランナブルがたくさんあります。ただし、各ランナブルは結果をファイルに書き込みます。したがって、現在、ランナブルのインターフェースは単純です。

class MyRunnable implements Runnable {
    ...
    MyRunnable(BufferedWriter writer, Task t) {
       this.writer = writer;
       this.task = t;
    }

    public void run() {
       ...
       this.writer.write(SOME_DATA);
    }
}

ただし、1 つの BufferedWriter (つまり、1 つの出力ファイル) を Executor プール内の各スレッドに関連付けたいと考えています。ただし、次のように.execute関数を呼び出しています。ExecutorService

BufferedWriter[] writers = initialize to 20 BufferedWriters;
ExecutorService executor = Executors.newFixedThreadPool(20);
for (Task t : tasks) {
    MyRunnable runnable = new MyRunnable(WHAT SHOULD GO HERE?, t)
    executor.execute(runnable);
}

エグゼキューターが特定のタスクを実行するためにどのスレッドを割り当てるかわからないため、どの BufferedWriter をランナブルに提供する必要があるかわかりません。ExecutorService によって管理される各スレッドが 1 つのオブジェクト (この場合は BufferedWriter) に関連付けられていることを確認するにはどうすればよいですか?

4

2 に答える 2

3

というクラスがありThreadLocalます。

例えば

ThreadLocal<Type> t = new ThreadLocal<>() {
    @Override protected Type initialValue() {
        return new Type(Thread.currentThread.getName());
}

Typeこれにより、新しいスレッドが にアクセスしようとするたびにa が遅延初期化されますt

前回このクラスを使用したのは、特定のマシンが最適に実行できるスレッド数を把握するためのクラスでした。(答えは通常「コア数」ですが、物理コアではなく仮想コアがこの数を駆動していることを確認したかったのです)。AtomicIntegerそこで、すべてのスレッドがカウンターをスパムするタスクを作成しました。しかし、すべてのスレッドが 1 つのカウンターをめぐって争っていたため、スレッドの競合に対処するために多くのオーバーヘッドが発生していたため、スレッドローカル カウンターを作成して、スレッドが他のスレッドからの干渉を受けずに独自のカウンターをスパムできるようにしました。

ほとんどの優れたマルチスレッド設計ではこれを回避しているため、使用例はやや不明瞭ですが、もちろん使用する場合もあります。

于 2013-10-20T23:50:50.007 に答える
2

... 1 つの BufferedWriter (つまり、1 つの出力ファイル) を Executor プール内の各スレッドに関連付けたい...

@djechlinの答えは良いですが、問題は、スレッドが最後のタスクの実行を終了したときにそれらにThreadLocalアクセスできないことです。BufferedWriterclose()

別の答えはここで見ることができます:

永続的なワーカー インスタンスを含むスレッドプール

その中で、独自BlockingQueueのタスクを作成し、スレッドごとに 1 つのタスクをフォークし、それらのスレッドにキューからタスクを取得させることをお勧めします。したがって、スレッド実行メソッドは次のようになります。

private final BlockingQueue<MyRunnable> queue = new ArrayBlockingQueue<>();
// if you want to shutdown your threads with a boolean
private volatile boolean shutdown;
...

// threads running in the `ExecutorService` will be doing this run() method
public void run() {
    // this allows them to maintain state, in this case your writer
    BufferedWriter writer = ...;
    while (!shutdown && !Thread.currentThread.isInterrupted()) {
        // they get their tasks from your own queue
        MyRunnable runnable = queue.take();
        // if you are using a poison pill but you'll have to add X of them
        if (runnable == STOP_OBJECT) {
            break;
        }
        runnable.run();
    }
    writer.close();
}

スレッドが完了したことをスレッドに伝えるのは、ここでは少し注意が必要です。「ポイズン ピル」オブジェクトをキューに追加することもできますが、実行中のスレッドと同じ数のオブジェクトをキューに追加する必要があります。

于 2013-10-21T00:04:48.260 に答える