[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Balking and JVM 1.2 vs. 1.1.5
- To: occam-com@xxxxxxxxx
- Subject: Balking and JVM 1.2 vs. 1.1.5
- From: Oyvind Teig <Oyvind.Teig@xxxxxxxxxxxx>
- Date: Fri, 5 Mar 1999 09:08:33 +0100
- Alternate-recipient: Allowed
- X400-mts-identifier: [/PRMD=autronica/ADMD=TELEMAX/C=NO/;8295 99/03/05 09:08]
- X400-originator: Oyvind.Teig@xxxxxxxxxxxx
- X400-received: by mta mail.autronica.no in /PRMD=autronica/ADMD=TELEMAX/C=NO/; Relayed; Fri, 5 Mar 1999 09:08:33 +0100
- X400-recipients: non-disclosure:;
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 "Patterns in Java, Volume 1" 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 "balk" 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 "flashes" it loops around incrementing a counter. </li>
* </ul>
* </blockquote>
*
* @version 1.0 5Mar1999
* @author Ø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 <=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) {};
}
}
}