BoundedExecutor
の実装については、Java Concurrency in Practiceの奇妙なことがあります。Java Concurrency in Practice:BoundedExecutorの競合状態ですか?
Executorにキューイングされているか実行中のスレッドが十分にある場合に、サブミットスレッドをブロックすることによってExecutorにタスクの送信を抑制することが想定されています。
これは(catch節で不足している再スローを追加した後)の実装です:
public class BoundedExecutor {
private final Executor exec;
private final Semaphore semaphore;
public BoundedExecutor(Executor exec, int bound) {
this.exec = exec;
this.semaphore = new Semaphore(bound);
}
public void submitTask(final Runnable command) throws InterruptedException, RejectedExecutionException {
semaphore.acquire();
try {
exec.execute(new Runnable() {
@Override public void run() {
try {
command.run();
} finally {
semaphore.release();
}
}
});
} catch (RejectedExecutionException e) {
semaphore.release();
throw e;
}
}
私はExecutors.newCachedThreadPool()
と4のバウンドでBoundedExecutor
をインスタンス化するとき、私はによってインスタンス化スレッドの数を期待しますキャッシュされたスレッドプールは決して4を超えることはありません。しかし、実際にはそうです。私は同じくらい11としてスレッドを作成するには、この小さなテストプログラムを得ている:
public static void main(String[] args) throws Exception {
class CountingThreadFactory implements ThreadFactory {
int count;
@Override public Thread newThread(Runnable r) {
++count;
return new Thread(r);
}
}
List<Integer> counts = new ArrayList<Integer>();
for (int n = 0; n < 100; ++n) {
CountingThreadFactory countingThreadFactory = new CountingThreadFactory();
ExecutorService exec = Executors.newCachedThreadPool(countingThreadFactory);
try {
BoundedExecutor be = new BoundedExecutor(exec, 4);
for (int i = 0; i < 20000; ++i) {
be.submitTask(new Runnable() {
@Override public void run() {}
});
}
} finally {
exec.shutdown();
}
counts.add(countingThreadFactory.count);
}
System.out.println(Collections.max(counts));
}
私は別のスレッドが許可証をAQUIREできるセマフォの解放とタスクの終了との間に小さな小さな時間枠は、あると思うし、解放スレッドがまだ終了していない間にタスクをサブミットしてください。言い換えれば、それは競合状態にある。
誰かがこれを確認できますか?
私はsemaphore.release()の直後に1msのThread.sleepを追加して、どれくらい悪くなったかを確認しました。私は300以上のスレッドを作成しました。 – toto2