Как an answer к question about pausing a BlockingQueue, я пришел с идеей использования существующей блокирующей структуры blockingQueue2
и охраны состояния двумя разными замками.Охранное состояние с двумя замками
public class BlockingQueueWithPause<E> extends LinkedBlockingQueue<E> {
private static final long serialVersionUID = 184661285402L;
private Object lock1 = new Object();//used in pause() and in take()
private Object lock2 = new Object();//used in pause() and unpause()
//@GuardedBy("lock1")
private volatile boolean paused;
private LinkedBlockingQueue<Object> blockingQueue2 = new LinkedBlockingQueue<Object>();
public void pause() {
if (!paused) {
synchronized (lock1) {
synchronized (lock2) {
if (!paused) {
paused = true;
blockingQueue2.removeAll();//make sure it is empty, e.g after successive calls to pause() and unpause() without any consumers it will remain unempty
}
}
}
}
}
public void unpause() throws InterruptedException {
if (paused) {
synchronized (lock2) {
paused = false;
blockingQueue2.put(new Object());//will release waiting thread, if there is one
}
}
}
@Override
public E take() throws InterruptedException {
E result = super.take();
if (paused) {
synchronized (lock1) {//this guarantees that a single thread will be in the synchronized block, all other threads will be waiting
if (paused) {
blockingQueue2.take();
}
}
}
return result;
}
//TODO override similarly the poll() method.
}
мне нужны два разных замки, в противном случае unpause()
может ждать lock1
состоялись уже в take()
потребительского потока.
Мои вопросы:
- Может ли это прийти в тупик?
- Это вообще работает?
- Как часто вы видите такой код, как я сам не считаю его доступным для чтения?
- Как я могу аннотировать флаг
paused
: с@GuardedBy("lock1, locks2")
?
PS: Любые улучшения приветствуются (кроме того, я мог бы использовать двоичный семафор вместо blockingQueue2
).
Хороший ответ: я нахожу ваше решение с более элегантным «Phaser», поскольку оно более кратким и не содержит сложных атомных операций. –
@AndreiI Спасибо, надеюсь, что он может работать. Это было весело для меня, мне понадобилось некоторое время, чтобы по-настоящему разобрать его :) –