import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.HashMap; public class LBDLockPatternTest { final int numTasks = 32; final int CAP = 10000; final ExecutorService m_executor; int m_counter; volatile int m_watch = 0; final LinkedBlockingDeque<Integer> m_lbd = new LinkedBlockingDeque<Integer>(CAP); final HashMap<Integer, LimitedTask> m_taskMap = new HashMap<Integer, LimitedTask>(); class LimitedTask { volatile boolean m_running = false; private final Object m_lock = new Object(); private long m_lastRunIndex = Long.MIN_VALUE; private Integer m_id; public LimitedTask(Integer id) { m_id = id; } public void lockForHandlingWork() { synchronized(m_lock) { if (m_running) { System.err.println("Attempted to run a limited task while it was already running"); System.exit(-1); } assert m_running == false; m_running = true; } } public void run(long runIndex) { try { if (runIndex < m_lastRunIndex) { System.err.println("Attempted to run a limited task out of order or with an old invocation"); System.exit(-1); } m_lastRunIndex = runIndex; m_lbd.poll(); } finally { synchronized (m_lock) { m_running = false; } synchronized (m_taskMap) { if (m_taskMap.put(m_id, this) != null) { System.err.println("Attempted to place limited task back in map when it was already present"); System.exit(-1); } } } } } class Offerer extends Thread { public void run() { while (true) { for (int i=0; i < CAP/4; ++i) m_lbd.offer(0); System.out.printf("."); if (m_lbd.size() > CAP / 2) { try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } } } } } public LBDLockPatternTest() { m_executor = new ThreadPoolExecutor(8, 8, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(CAP)); ((ThreadPoolExecutor)m_executor).setRejectedExecutionHandler( new ThreadPoolExecutor.DiscardPolicy()); } public void runTest() { for (int ii = 0; ii < numTasks; ii++) { m_taskMap.put(ii, new LimitedTask(ii)); } new Offerer().start(); long runIndex = Long.MIN_VALUE; java.util.Random r = new java.util.Random(); while (true) { runIndex++; LimitedTask nextTask = null; while (nextTask == null) { synchronized (m_taskMap) { nextTask = m_taskMap.remove(r.nextInt(numTasks)); } } final LimitedTask theTask = nextTask; final long theIndex = runIndex; theTask.lockForHandlingWork(); m_executor.execute(new Runnable() { @Override public void run() { theTask.run(theIndex); } }); } } public static void main(String[] args) { LBDLockPatternTest that = new LBDLockPatternTest(); that.runTest(); } }