/* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ // Yet another contended object monitor throughput test // adapted from bug reports import java.util.*; import java.lang.*; import java.util.concurrent.*; import java.util.concurrent.locks.*; class Producer extends Thread { // private static Hashtable buddiesOnline = new Hashtable(); private static Map buddiesOnline = new ConcurrentHashMap(); public Producer (String name) { super(name); } public void run() { Object key = null ; final ReentrantLock dr = RLJBar.DeathRow; final ReentrantLock bar = RLJBar.bar; final ReentrantLock end = RLJBar.End; final Condition endCondition = RLJBar.EndCondition; if (RLJBar.OneKey) key = new Integer(0) ; // per-thread v. per iteration // The barrier has a number of interesting effects: // 1. It enforces full LWP provisioning on T1. // (nearly all workers park concurrently). // 2. It gives the C2 compiler thread(s) a chance to run. // By transiently quiescing the workings the C2 threads // might avoid starvation. // try { bar.lock(); try { ++RLJBar.nUp ; if (RLJBar.nUp == RLJBar.nThreads) { if (RLJBar.quiesce != 0) { RLJBar.barCondition.awaitNanos(RLJBar.quiesce * 1000000) ; } RLJBar.epoch = System.currentTimeMillis () ; RLJBar.barCondition.signalAll () ; // System.out.print ("Consensus ") ; } if (RLJBar.UseBar) { while (RLJBar.nUp != RLJBar.nThreads) { RLJBar.barCondition.await () ; } } } finally { bar.unlock(); } } catch (Exception ex) { System.out.println ("Exception in barrier: " + ex) ; } // Main execution time ... the code being timed ... // HashTable.get() is highly contended (serial). for (int loop = 1; loop < 100000 ;loop++) { if (!RLJBar.OneKey) key = new Integer(0) ; buddiesOnline.get(key); } // Mutator epilog: // The following code determines if the test will/wont include (measure) // thread death time. end.lock(); try { ++RLJBar.nDead ; if (RLJBar.nDead == RLJBar.nUp) { // System.out.print((System.currentTimeMillis()-RLJBar.epoch) + " ms") ; endCondition.signalAll() ; } } finally { end.unlock(); } dr.lock(); dr.unlock(); } } public class RLJBar // ProdConsTest { public static final int ITERS = 10; public static boolean OneKey = false ; // alloc once or once per iteration public static boolean UseBar = false ; public static int nThreads = 100 ; public static int nUp = 0 ; public static int nDead = 0 ; public static ReentrantLock bar = new ReentrantLock() ; public static Condition barCondition = bar.newCondition() ; public static long epoch ; public static ReentrantLock DeathRow = new ReentrantLock () ; public static ReentrantLock End = new ReentrantLock () ; public static int quiesce = 0 ; public static Condition EndCondition = End.newCondition(); public static void main (String[] args) { int argix = 0 ; if (argix < args.length && args[argix].equals("-o")) { ++argix ; OneKey = true ; System.out.println ("OneKey") ; } if (argix < args.length && args[argix].equals ("-b")) { ++argix ; UseBar = true ; System.out.println ("UseBar") ; } if (argix < args.length && args[argix].equals ("-q")) { ++argix ; if (argix < args.length) { quiesce = Integer.parseInt (args[argix++]) ; System.out.println ("Quiesce " + quiesce + " msecs") ; } } for (int k = 0; k < ITERS; ++k) oneRun(); } public static void oneRun() { DeathRow = new ReentrantLock () ; End = new ReentrantLock () ; EndCondition = End.newCondition(); nDead = nUp = 0 ; long cyBase = System.currentTimeMillis () ; DeathRow.lock(); try { for (int i = 1; i <= nThreads ; i++) { new Producer("Producer" + i).start(); } try { End.lock(); try { while (nDead != nThreads) EndCondition.await() ; } finally { End.unlock(); } } catch (Exception ex) { System.out.println ("Exception in End: " + ex) ; } } finally { DeathRow.unlock(); } System.out.println ("Outer time: " + (System.currentTimeMillis()-cyBase)) ; // Let workers quiesce/exit. try { Thread.sleep (1000) ; } catch (Exception ex) {} ; } }