package org.jgroups.util; import java.util.Collection; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.locks.ReentrantLock; /** * A queue with many producers and consumers. However, only <em>one</em> consumer gets to remove and process elements * at any given time. This is done through the use of locks. * @author Bela Ban * @since 3.5 */ public class ProcessingQueue<T> { protected final java.util.Queue<T> queue=new ConcurrentLinkedQueue<>(); protected final ReentrantLock producer_lock=new ReentrantLock(), consumer_lock=new ReentrantLock(); protected int count=0; protected Handler<T> handler; public java.util.Queue<T> getQueue() {return queue;} public int size() {return queue.size();} public ProcessingQueue<T> setHandler(Handler<T> handler) {this.handler=handler; return this;} public void add(T element) { producer_lock.lock(); try { queue.add(element); count++; } finally { producer_lock.unlock(); } process(); } public boolean retainAll(Collection<T> elements) { return queue.retainAll(elements); } public String toString() { return queue.toString(); } protected void process() { if(consumer_lock.tryLock()) { try { while(true) { T element=queue.poll(); if(element != null && handler != null) { try { handler.handle(element); } catch(Throwable t) { t.printStackTrace(System.err); } } producer_lock.lock(); try { if(count == 0 || count-1 == 0) { count=0; consumer_lock.unlock(); return; } count--; } finally { producer_lock.unlock(); } } } finally { if(consumer_lock.isHeldByCurrentThread()) consumer_lock.unlock(); } } } public interface Handler<T> { void handle(T element); } }