/* * 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/publicdomain/zero/1.0/ */ // Yet another contended object monitor throughput test // adapted from bug reports import java.util.*; 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) {}; } }