package org.dynmap; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.LinkedBlockingQueue; public class AsynchronousQueue<T> { private Object lock = new Object(); private Thread thread; private LinkedBlockingQueue<T> queue = new LinkedBlockingQueue<T>(); private Set<T> set = new HashSet<T>(); private Handler<T> handler; private int dequeueTime; private int accelDequeueTime; public int accelDequeueThresh; private int pendingcnt; private int pendinglimit; private boolean normalprio; public AsynchronousQueue(Handler<T> handler, int dequeueTime, int accelDequeueThresh, int accelDequeueTime, int pendinglimit, boolean normalprio) { this.handler = handler; this.dequeueTime = dequeueTime; this.accelDequeueTime = accelDequeueTime; this.accelDequeueThresh = accelDequeueThresh; if(pendinglimit < 1) pendinglimit = 1; this.pendinglimit = pendinglimit; this.normalprio = normalprio; } public boolean push(T t) { synchronized (lock) { if (!set.add(t)) { return false; } } queue.offer(t); return true; } private T pop() { try { T t = queue.take(); synchronized (lock) { set.remove(t); } return t; } catch (InterruptedException ix) { return null; } } public boolean remove(T t) { synchronized (lock) { if (set.remove(t)) { queue.remove(t); return true; } } return false; } public int size() { return set.size(); } public List<T> popAll() { List<T> s; synchronized(lock) { s = new ArrayList<T>(queue); queue.clear(); set.clear(); } return s; } public void start() { synchronized (lock) { thread = new Thread(new Runnable() { @Override public void run() { running(); } }); thread.start(); try { if(!normalprio) thread.setPriority(Thread.MIN_PRIORITY); } catch (SecurityException e) { Log.info("Failed to set minimum priority for worker thread!"); } } } public void stop() { synchronized (lock) { if (thread == null) return; Thread oldThread = thread; thread = null; Log.info("Stopping map renderer..."); oldThread.interrupt(); try { oldThread.join(1000); } catch (InterruptedException e) { Log.info("Waiting for map renderer to stop is interrupted"); } } } private void running() { try { while (Thread.currentThread() == thread) { synchronized(lock) { while(pendingcnt >= pendinglimit) { try { lock.wait(accelDequeueTime); } catch (InterruptedException ix) { if(Thread.currentThread() != thread) return; throw ix; } } } T t = pop(); if (t != null) { synchronized(lock) { pendingcnt++; } handler.handle(t); } if(set.size() >= accelDequeueThresh) sleep(accelDequeueTime); else sleep(dequeueTime); } } catch (Exception ex) { Log.severe("Exception on rendering-thread", ex); } } private boolean sleep(int time) { try { Thread.sleep(time); } catch (InterruptedException e) { return false; } return true; } public void done(T t) { synchronized (lock) { if(pendingcnt > 0) pendingcnt--; lock.notifyAll(); } } }