[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Balking and JVM 1.2 vs. 1.1.5



All

I try this on occam-com, since java-threads seem so dead,
and this groups seems so vivid.

I have written a program to prove that Mark Grand's example
of the Balking Concurrency Pattern in Patterns in Java, Vol 1
is at best not a good pattern for any real implementation.

(Code is attached for those who are interested. I've had some
communication with Mark Grand also, not attached.)

Clip from output from JVM 1.2:
===============================

Starter 1      balkCounter= 150
Stopper     B                              stopCounter= 263
Starter  2                  notifyCounter= 104
Stopper      C                             stopCounter= 264
Starter   3                 notifyCounter= 105
Stopper    A                               stopCounter= 265
Stopper     B                              stopCounter= 266
Stopper     B                              stopCounter= 267
Starter   3                 notifyCounter= 106
Starter 1      balkCounter= 151

Gracefully terminated after 60 seconds
1 Pulser, 3 Starter and 3 Stopper threads were running
42.478752 ns per pulserCounter increment (normalized to dutyCycle 
1.0)
Duty cycle 0.5706667

Clip from output from JVM 1.2:
===============================
Starter   3    balkCounter= 164
Starter  2     balkCounter= 165
Starter 1      balkCounter= 166
Stopper      C                             stopCounter= 253
Stopper    A                               stopCounter= 254
Stopper     B                              stopCounter= 255
Starter 1                   notifyCounter= 103
Starter   3    balkCounter= 167
Starter  2     balkCounter= 168

Gracefully terminated after 60 seconds
1 Pulser, 3 Starter and 3 Stopper threads were running
920.17847 ns per pulserCounter increment (normalized to dutyCycle 
1.0)
Duty cycle 0.40383333

===============================================================
See the speed difference?
42ns vs. 920ns for a normalized increment?
It seems rather reproducable.
I run Sun's JVM on Win95.
Is there anything wrong (with me)?
===============================================================

-- 

|==================================================================|
| Oyvind Teig                             oyvind.teig@xxxxxxxxxxxx |
| Navia Maritime AS, division Autronica   oyvind.teig@xxxxxxxxxxxx |
| 7005 Trondhem                              Tel.: +47 73 58 12 68 |
| Norway           http://www.autronica.no   Fax.: +47 73 91 93 20 |
|==================================================================|
import java.util.Random;
/**
 * <h2>An implementation of the <em><b>Balking</b></em> Concurrency Pattern</h2>
 *
 * <blockquote>
 *   <p>Written by Øyvind Teig, <a href="mailto:oyvind.teig@xxxxxxxxxxxx";>oyvind.teig@xxxxxxxxxxxx</a>
 *   <br>
 *   Inspired from &quot;Patterns in Java, Volume 1&quot; by <i>Mark Grand</i>. </p>
 * </blockquote>
 *
 * <h3>Background</h3>
 *
 * <blockquote>
 *   <p>See <a href="Balking.htm">Balking.htm</a></p>
 * </blockquote>
 *
 * <h3>Architecture</h3>
 *
 * <blockquote>
 *   <ul>
 *     <li>1 instance of <strong>Pulser_thread_balking_example</strong> (which is the <em>Balking</em> example
 *       proper) is started.</li>
 *     <li>3 instances of <strong>Starter_thread</strong> are started.</li>
 *     <li>3 instances of <strong>Stopper_thread</strong> are started.</li>
 *     <li>All 3 Starter_thread repeatedly start flashing in Pulser_thread_balking_example, then they wait randomly
 *       with an average of 500ms. This starting will &quot;balk&quot; if Pulser_thread_balking_example is already
 *       flashing.</li>
 *     <li>All 3 Stopper_thread repeatedly stop flashing in Pulser_thread_balking_example, then they wait randomly
 *       with an average of 500ms. </li>
 *     <li>There are therefore equally many starts and stops - but some of the starts will fail (<em>balk</em>).
 *       We saw that, under Linux, the Kaffe JVM with this program, was active for 45% of the time,
 *       with more than enough machine resources.</li>
 *     <li>When Pulse_thread &quot;flashes&quot; it loops around incrementing a counter. </li>
 *   </ul>
 * </blockquote>
 *
 * @version 1.0 5Mar1999
 * @author &Oslash;yvind Teig, <a href="mailto:oyvind.teig@xxxxxxxxxxxx";>oyvind.teig@xxxxxxxxxxxx</a>
 */
public class Flasher {

   /**
    * Flasher <b>main</b> runs the test program for a specified time.
    *
    * @param argv <i>seconds</i>: number of seconds, a value &lt;=0 is "forever"
    */
   public static void main (String argv[]) {

      if (argv.length != 1) {
         System.out.println ("\nFlasher - an example of the \"Balking\" Concurrency Pattern");
         System.out.println ("5Mar1999, oyvind.teig@xxxxxxxxxxxx");
         System.out.println ("Inspired by Mark Grand, \"Patterns in Java\", Vol.1\n");

         System.err.println ("Usage:");
         System.err.println ("  java Flasher <seconds to run>");
         System.err.println ("  Negative or zero <seconds to run> is 'forever'\n");
      } else {
         Integer arg0 = new Integer(argv[0]);
         long seconds;

         try {arg0 = arg0.valueOf(argv[0]);} catch (NumberFormatException e) {};
         seconds = arg0.longValue();

         if (seconds <= 0) {
            System.out.println ("\nWill run forever, hit Ctrl-C to stop\n");
            try {Thread.sleep(4*1000);} catch (InterruptedException e) {};
         }
         System.out.println ("");

         Pulser_thread_balking_example pulser    = new Pulser_thread_balking_example();

         Starter_thread starter_1 = new Starter_thread ("Starter 1      ", pulser);
         Starter_thread starter_2 = new Starter_thread ("Starter  2     ", pulser);
         Starter_thread starter_3 = new Starter_thread ("Starter   3    ", pulser);
         Stopper_thread stopper_A = new Stopper_thread ("Stopper    A   ", pulser);
         Stopper_thread stopper_B = new Stopper_thread ("Stopper     B  ", pulser);
         Stopper_thread stopper_C = new Stopper_thread ("Stopper      C ", pulser);

         if (seconds > 0) {
            long ms = seconds*1000;
            try {Thread.sleep(ms);} catch (InterruptedException e) {};

            starter_1.stopIt();
            starter_2.stopIt();
            starter_3.stopIt();
            stopper_A.stopIt();
            stopper_B.stopIt();
            stopper_C.stopIt();
            {
               long  timeAccum_ms  = pulser.get_timeAccum_ms();
               long  pulserCounter = pulser.stopIt();
               float dutyCycle     = (float)timeAccum_ms/(float)ms; // 0..1
               float timePerInc_ns = ((float)timeAccum_ms/(float)pulserCounter) * 1000000;
               //
               System.out.println ("\nGracefully terminated after " + seconds + " seconds");
               System.out.println ("1 Pulser, 3 Starter and 3 Stopper threads were running");
               System.out.println (timePerInc_ns + " ns per pulserCounter increment (normalized to dutyCycle 1.0)");
               System.out.println ("Duty cycle " + dutyCycle + "\n");
            }
         }
      }
   }
}
/**
 * This class gives an example that may balk. The method stop_pulsing is the
 * method that may balk.
 */
class Pulser_thread_balking_example extends Thread {
   /**
    * Used in while-loop in run method below.
    * This is the only way to terminate a thread for Java 1.2, where Thread.stop()
    * has been rightfully deprecated.
    */
   private boolean running = true;

   /**
    * Main state variable, used to "flash" and "balk".
    * Set to true by start_pulsing and to false by stop_pulsing.
    * This class will "flash" as long as flashingInProgress is true,
    * in which case it will also balk. It has to be set to false
    * to avoid balking.
    */
   private boolean flashingInProgress = false;

   /**
    * In this class, flashing means incrementing this counter.
    * This variable is not needed, we just use it to envisage flashing.
    */
   private long flashCounter = 0;

   /**
    * Whenever start_pulsing balks, this counter is incremented.
    * This variable is not needed, we just use it to envisage balking.
    */
   private long balkCounter = 0;

   /**
    * Whenever start_pulsing does not balk, this counter is incremented.
    * This variable is not needed, we just use it to envisage not balking.
    * Increments every time start_pulsing <i>notifies</i> the run method.
    */
   private long notifyCounter = 0;

   /**
    * Whenever stop_pulsing is called, this counter is incremented.
    * This variable is not needed, we just use it to envisage stopping.
    */
   private long stopCounter = 0;

   /**
    * We want to measure how much of the time it spends flashing.
    * We need timePre_ms and timeAccum_ms for this.
    */
   private long timePre_ms = 0;
   private long timeAccum_ms = 0;

   /**
    *  The constructor starts the run-method.
    */
   public Pulser_thread_balking_example() {
      this.start();
   }

   /**
    * If this class is flashing, start_pulsing balks, increments balkCounter,
    * prints out a message and returns.
    * If this class is not flashing, start_pulsing will start flashing by
    * setting flashingInProgress to true, <i>notify</i> the run-method (which takes the
    * notify if it <i>wait</i>s for it). In addition, start_pulsing will increment
    * notifyCounter and print out a line.
    */
   public synchronized void start_pulsing (String name) {
      if (flashingInProgress == true) {
         balkCounter++;
         System.out.println (name + "balkCounter= " + balkCounter);
      }
      else {
         flashingInProgress = true;
         this.notify();
         notifyCounter++;
         timePre_ms = System.currentTimeMillis();
         System.out.println (name + "             notifyCounter= " + notifyCounter);
      }
   }

   /**
    * Method to stop flashing.
    * Will clear flashingInProgress, increment stopCounter and print out a line.
    */
   public synchronized void stop_pulsing (String name) {
      if (flashingInProgress == true) {
        timeAccum_ms = timeAccum_ms + (System.currentTimeMillis() - timePre_ms);
      }
      flashingInProgress = false;
      stopCounter++;
      System.out.println    (name + "                            stopCounter= " + stopCounter);
   }

   /**
    * I have called the stop method <i>stopIt</i> so that I can compile this code
    * under Java 1.1.5 as well. As mentioned, Thread.stop has been deprecated.
    * The only way to stop a thread now is to do it gracefully from inside. We
    * first notify the run method so that it will awake should it wait. Then
    * we clear running, which will cause the run-method's while-loop to terminate.
    * This method and the while-loop in the run.method is actually a Concurrency
    * pattern on its own.
    *
    * @return flashCounter, we want to have this value as "atomic" as possible,
    *         that's why we haven't made a separate getflashCounter method.
    */
   public synchronized long stopIt() {
      this.notify();
      running = false;
      return (flashCounter);
   }

   /**
    * @return Accumulated time that the unit was "flashing"
    */
   public synchronized long get_timeAccum_ms() {
      return (timeAccum_ms);
   }
   /**
    * This is the thread, so to say.
    * It loops around in its while-loop as long as running is true. If it flashes,
    * the flashCounter is incremented. If, however, flashingInProgress is false,
    * it will <i>wait</i> until start_pulsing <i>notify</i> it. Observe that both
    * wait and signal must be wrapped up in a <i>synchronized</i> statement, so
    * that the parties get ownership of their own <i>monitor</i> before they use it.
    */
   public void run() {
      while (running) {
         if (flashingInProgress == false) {
            synchronized (this) {
               try {wait();}
               catch (InterruptedException e) {};
            }
         } else {
            flashCounter++; // This is per definition the "flashing"
         }
      }
   }
}
// ---------------------------------------------------------------------------------------------
// Starter_thread doesn't give up starting a server, but it does not know that it may fail:
// ---------------------------------------------------------------------------------------------
class Starter_thread extends Thread {
   private boolean running = true;
   private String name;
   private Pulser_thread_balking_example pulser;
   private Random ran = new Random();

   public Starter_thread (String name, Pulser_thread_balking_example pulser) {
      this.name = name;
      this.pulser = pulser;
      start();
   }
   public synchronized void stopIt() {
      running = false;
   }
   public void run() {
      while (running) {
         pulser.start_pulsing (name);
         try {Thread.sleep((long)(ran.nextFloat() * 1000));} catch (InterruptedException e) {};
      }
   }
}
// ---------------------------------------------------------------------------------------------
// Stopper_thread doesn't give up stopping a server:
// ---------------------------------------------------------------------------------------------
class Stopper_thread extends Thread {
   private boolean running = true;
   private String name;
   private Pulser_thread_balking_example pulser;
   private Random ran = new Random();

   public Stopper_thread (String name, Pulser_thread_balking_example pulser) {
      this.name = name;
      this.pulser = pulser;
      start();
   }
   public synchronized void stopIt() {
      running = false;
   }
   public void run() {
      while (running) {
         pulser.stop_pulsing (name);
         try {Thread.sleep((long)(ran.nextFloat() * 1000));} catch (InterruptedException e) {};
      }
   }
}