Вы могли попытаться использовать плагин Firebug для Firefox для просмотра CSS на кнопке.
java.util.concurrent.Phaser
похоже, что он подойдет вам. Планируется, что он будет выпущен в Java 7, но наиболее стабильную версию можно найти на сайте группы интересов jsr166 .
Фейзер - это прославленный Cyclic Barrier. Вы можете зарегистрировать N групп, и когда будете готовы, дождитесь их продвижения на определенном этапе.
Быстрый пример того, как это будет работать:
final Phaser phaser = new Phaser();
public Runnable getRunnable(){
return new Runnable(){
public void run(){
..do stuff...
phaser.arriveAndDeregister();
}
};
}
public void doWork(){
phaser.register();//register self
for(int i=0 ; i < N; i++){
phaser.register(); // register this task prior to execution
executor.submit( getRunnable());
}
phaser.arriveAndAwaitAdvance();
}
Я предполагаю, что вашему производителю не нужно знать, когда очередь пуста, но ему нужно знать, когда последняя задача была завершена.
Я бы добавил метод waitforWorkDone (производитель)
для потребителя. Производитель может добавить свои N задач и вызвать метод ожидания. Метод ожидания блокирует входящий поток, если рабочая очередь не пуста и в данный момент никакие задачи не выполняются.
Потоки-потребители notifyAll ()
на ожидании блокировки, если их задача завершена, очередь пуста и никакая другая задача не выполняется.
Вы, конечно, можете использовать CountDownLatch
, защищенный AtomicReference
, чтобы ваши задачи были упакованы таким образом:
public class MyTask extends Runnable {
private final Runnable r;
public MyTask(Runnable r, AtomicReference<CountDownLatch> l) { this.r = r; }
public void run() {
r.run();
while (l.get() == null) Thread.sleep(1000L); //handle Interrupted
l.get().countDown();
}
}
Обратите внимание , что задачи выполняют свою работу, а затем вращают до тех пор, пока не будет установлен обратный отсчет (т. е. общее количество задач станет известным). Как только обратный отсчет установлен, они начинают обратный отсчет и выходят. Они отправляются следующим образом:
AtomicReference<CountDownLatch> l = new AtomicReference<CountDownLatch>();
executor.submit(new MyTask(r, l));
После точки создания / отправки вашей работы, , когда вы знаете, сколько задач вы создали :
latch.set(new CountDownLatch(nTasks));
latch.get().await();
Я использовал ExecutorCompletionService для чего-то вроде этого:
ExecutorCompletionService executor = ...;
int count = 0;
while (...) {
executor.submit(new Processor());
count++;
}
//Now, pull the futures out of the queue:
for (int i = 0; i < count; i++) {
executor.take().get();
}
Это включает в себя хранение очереди отправленных задач, поэтому, если ваш список произвольно длинный, ваш метод может быть лучше.
Но не забудьте использовать AtomicInteger
для координации, чтобы вы могли увеличивать его в одном потоке и уменьшать в рабочих потоках.