code: // from gee.cs.oswego.edu/home/jsr166/jsr166
  
  package jsr166tests.loops;
  
  /*
   * 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
   */
  // Adapted from code that was in turn
  // Derived from SocketPerformanceTest.java - BugID: 4763450
  //
  //
  
  import java.io.*;
  import java.net.*;
  import java.util.concurrent.*;
  import java.util.concurrent.locks.*;
  
  public class RLIBar {
  
      static int batchLimit ;
      static int mseq ;
      static int nReady ;
      static int ExThreads ;
      static int ASum ;
      static final ReentrantLock Gate = new ReentrantLock () ;
      static final Condition GateCond = Gate.newCondition () ;
  
      static final ReentrantLock HoldQ = new ReentrantLock () ;
      static final Condition HoldQCond = HoldQ.newCondition() ;
      static boolean Hold = false ;
      static int HoldPop ;
      static int HoldLimit ;
  
      static private boolean HoldCheck () {
          try {
              HoldQ.lock();
              try {
                  if (!Hold) return false;
                  else {
                      ++HoldPop ;
                      if (HoldPop >= HoldLimit) {
                          System.out.print ("Holding ") ;
                          Thread.sleep (1000) ;
                          System.out.println () ;
                          Hold = false ;
                          HoldQCond.signalAll () ;
                      }
                      else
                          while (Hold)
                              HoldQCond.await() ;
  
                      if (--HoldPop == 0) HoldQCond.signalAll () ;
                      return true;
                  }
              }
              finally {
                  HoldQ.unlock();
              }
          } catch (Exception Ex) {
              System.out.println ("Unexpected exception in Hold: " + Ex) ;
              return false;
          }
      }
  
      private static class Server {
          private int nClients;
          final ReentrantLock thisLock = new ReentrantLock();
          final Condition thisCond = thisLock.newCondition();
  
          Server (int nClients) {
              this.nClients = nClients;
              try {
                  for (int i = 0; i < nClients; ++i) {
                      final int fix = i ;
                      new Thread() { public void run () { runServer(fix); }}.start();
                  }
              } catch (Exception e) {
                  System.err.println(e) ;
              }
          }
  
          // the total number of messages received by all server threads
          // on this server
          int msgsReceived = 0;
  
          // incremented each time we get a complete batch of requests
          private int currentBatch = 0;
  
          // the number of requests received since the last time currentBatch
          // was incremented
          private int currentBatchSize = 0;
  
          private void runServer (int id) {
              int msg ;
              boolean held = false;
              final ReentrantLock thisLock = this.thisLock;
              final Condition thisCond = this.thisCond;
  
              try {
  
                  // Startup barrier - rendezvous - wait for all threads.
                  // Forces all threads to park on their LWPs, ensuring
                  // proper provisioning on T1.
                  // Alternately, use THR_BOUND threads
                  Gate.lock(); try {
                      ++nReady ;
                      if (nReady == ExThreads ) {
                          GateCond.signalAll () ;
                      }
                      while (nReady != ExThreads )
                          GateCond.await() ;
                  } finally { Gate.unlock(); }
  
                  for (;;) {
                      //                    if (!held && currentBatchSize == 0) held = HoldCheck () ;
                      msg = (++ mseq) ^ id ;
                      thisLock.lock();
                      try {
                          ASum += msg ;
                          ++msgsReceived;
                          int myBatch = currentBatch;
                          if (++currentBatchSize >= batchLimit) {
                              // this batch is full, start a new one ...
                              ++currentBatch;
                              currentBatchSize = 0;
                              // and wake up everyone in this one
                              thisCond.signalAll () ;
                          }
                          // Wait until our batch is complete
                          while (myBatch == currentBatch)
                              thisCond.await();
                      }
                      finally {
                          thisLock.unlock();
                      }
                  }
              } catch (Exception e) {
                  System.err.println("Server thread: exception "  + e) ;
                  e.printStackTrace();
              }
          }
  
  
      }
  
      public static void main (String[] args) throws Exception {
          int nServers = 10 ;
          int nClients = 10 ;
          int samplePeriod = 10000;
          int nSamples = 5;
  
          int nextArg = 0;
          while (nextArg < args.length) {
              String arg = args[nextArg++];
              if (arg.equals("-nc"))
                  nClients = Integer.parseInt(args[nextArg++]);
              else if (arg.equals("-ns"))
                  nServers = Integer.parseInt(args[nextArg++]);
              else if (arg.equals("-batch"))
                  batchLimit = Integer.parseInt(args[nextArg++]);
              else if (arg.equals("-sample"))
                  samplePeriod = Integer.parseInt(args[nextArg++]);
              else if (arg.equals("-np"))
                  nSamples = Integer.parseInt(args[nextArg++]);
              else {
                  System.err.println ("Argument error:" + arg) ;
                  System.exit (1) ;
              }
          }
          if (nClients <= 0 || nServers <= 0 || samplePeriod <= 0 || batchLimit > nClients) {
              System.err.println ("Argument error") ;
              System.exit (1) ;
          }
  
          // default batch size is 2/3 the number of clients
          // (for no particular reason)
          if (false && batchLimit <= 0)
              batchLimit = (2 * nClients + 1) / 3;
  
          ExThreads = nServers * nClients ; 	// expected # of threads
          HoldLimit = ExThreads ;
  
          // start up all threads
          Server[] servers = new Server[nServers];
          for (int i = 0; i < nServers; ++i) {
              servers[i] = new Server(nClients);
          }
  
          // Wait for consensus
          try {
              Gate.lock(); try {
                  while (nReady != ExThreads ) GateCond.await() ;
              } finally { Gate.unlock(); }
          } catch (Exception ex) {
              System.out.println (ex);
          }
          System.out.println (
                              nReady + " Ready: nc=" + nClients + " ns=" + nServers + " batch=" + batchLimit) ;
  
          // Start sampling ...
          // Methodological problem: all the mutator threads
          // can starve the compiler threads, resulting in skewed scores.
          // In theory, over time, the scores will improve as the compiler
          // threads are granted CPU cycles, but in practice a "warm up" phase
          // might be good idea to help C2.  For this reason I've implemented
          // the "Hold" facility.
  
          long lastNumMsgs = 0;
          long sampleStart = System.currentTimeMillis();
          for (int j = 0; j < nSamples; ++j) {
              // when this sample period is supposed to end
              long sampleEnd = sampleStart + samplePeriod;
              for (;;) {
                  long now = System.currentTimeMillis();
                  if (now >= sampleEnd) {
                      // when it really did end
                      sampleEnd = now;
                      break;
                  }
                  Thread.sleep(sampleEnd - now);
              }
  
              if (false && j == 2) {
                  System.out.print ("Hold activated ...") ;
                  HoldQ.lock();
                  try  {
                      Hold = true ;
                      while (Hold) HoldQCond.await() ;
                  }
                  finally {
                      HoldQ.unlock();
                  }
              }
  
  
  
              // there's no synchronization here, so the total i get is
              // approximate, but that's OK since any i miss for this
              // sample will get credited to the next sample, and on average
              // we'll be right
              long numMsgs = 0;
              for (int i = 0; i < nServers; ++i)
                  numMsgs += servers[i].msgsReceived;
              long deltaMsgs = numMsgs - lastNumMsgs;
              long deltaT = sampleEnd - sampleStart;
              if (true || j != 2) { 	// Don't report results if we issued a hold ...
                  System.out.print(
                                   "Sample period = " + deltaT + " ms; "
                                   + "New msgs rcvd = " + deltaMsgs + "; "
                                   + "Throughput = " + (deltaMsgs*1000 / deltaT) + " msg/sec\n");
                  //                for (int i = 0; i < nServers; ++i)
                  //                    servers[i].thisLock.dump();
              }
              sampleStart = sampleEnd;
              lastNumMsgs = numMsgs;
          }
          System.exit(0);
      }
  }
  