R
Renato Battaglia
// JAVA THREADS - A JAVA BUG? Hope not!PLEASE ANYBODY HELP ME! Read on, folks...
// Name this "Reader.java"... copy-paste it into your programm editor!
// Example of a command line that did well on my fast Pentium-Linux:
// java Reader . 1500000
// YES I KNOW it will eat your CPU cycles, but running is brief!
// PS: On my sloooow Windows machine, i use "c:\ 1000" instead of ". 1500000"!
/*
Code below (just after my cry for help) is MEANT to be buggy.
I mean... "Watcher" threads will try to SYNCH(lock) then WAIT on
"Calculator" when, actually, "Calculator" already has a lock.
"Calculator" is meant to issue a "notify" when there are still no
"Watcher" waiting on it...
So... as long as "Calculator" will never again issue a "notify", "Watcher"
threads are supposed to remain blocked, "waiting" for a never-happening event.
This is exactly what happens when "class Calculator implements Runnable".
But... oddly enough, whenever I make a simple change in "Class Calculator"
code, just making it "extends Thread" instead of "implements Runnable", madness
comes by!!!!!!!!!!!!!!!!
Behavior changes, and , immediately after method "Calculator.run()"
returns, the "c.wait()" code in "Watcher.run()" also returns!! ISN´T THAT
WRONG?
The "c.wait()" call should block forever, shouldn´t it? Boy...
I am by no means a Java Guru... and, in my first contacts with Java threading,
I face such strange stuff. Blessing or a curse?
Anyway... I can´t express myself much better than this. Hope you,
experienced Java folks, have some fun on cracking this (bug?) out.
PS: I am really eagger to receive some replies showing me how wrong
I am, and what I am doing wrong, because I fell hopelessly lost on this matter,
right now.
(e-mail address removed)
(+55) 11 55082813
(+55) 11 55082817
*/
import java.io.*;
public class Reader
{
static String delayDirectory;
static int delayIterations;
public static void main(String argv[]) throws Exception
{
if (argv.length != 2)
{
System.err.println("Usage: java Reader [directory] [iterations]");
return;
}
delayDirectory = argv[0];
delayIterations = Integer.parseInt(argv[1]);
// please, adjust ITERATIONS and DIRECTORY to make delay
//(in Calculator.run()" take a few second... 4 or 5 seconds would
// be great for the purpose of this code-sample.
// PS: Don´t put a "sleep" there... "sleep" would release the
// object-lock, altering the behavior.
Calculator calculator = new Calculator ();
//new Thread(calculator).start();//if Calculator implements Runnable
calculator.start();//if Calculator extends Thread
new Watcher(calculator,"Th A").start();
new Watcher(calculator,"Th B").start();
new Watcher(calculator,"Th C").start();
//add as many of these Watcher-thread instantiations as you please.
}
}
class Watcher extends Thread
{
Calculator c;
String n;
public Watcher(Calculator calc,String nome)
{
c=calc;
n=nome;
}
public void run()
{
try { Thread.sleep((int)(2*1000)); } catch (InterruptedException e) {}
System.out.println(n + " before synchronizing on [Calculator c] object");
synchronized(c) {
try {
System.out.println(n + " Within synch - will Wait for calculation");
c.wait();
System.out.println(n + " WIthin synch - After waiting for calculation");
} catch (InterruptedException e) {}
}
System.out.println(n + " outside synch - Total value is " + c.total);
}
}
class Calculator extends Thread
// switch between "implements Runnable" and "extends Thread" on the line above
// Do not forget to modify function "main" accordingly.
// Do that... and watch strange difference in program behavior!
{
int total;
public void run()
{
System.out.println("Calculator-before synch on Calculator object");
synchronized(this) {
System.out.println("Calculator-within synched code-will calculate");
for (int i=0; i<Reader.delayIterations; i++)
{
total ++;
File f = new File(Reader.delayDirectory);
File fList[] = f.listFiles();
}
System.out.println("Calculator-done calculating... will notify!");
notify();
System.out.println("Calculator-has notified.");
}
System.out.println("Calculator-outside synch-before an arbitrary delay");
for (int i=0; i<Reader.delayIterations; i++)
{
File f = new File(Reader.delayDirectory);
File fList[] = f.listFiles();
}
System.out.println("Calculator-outside synch-after delay- HERE I DIE");
}
}
// Name this "Reader.java"... copy-paste it into your programm editor!
// Example of a command line that did well on my fast Pentium-Linux:
// java Reader . 1500000
// YES I KNOW it will eat your CPU cycles, but running is brief!
// PS: On my sloooow Windows machine, i use "c:\ 1000" instead of ". 1500000"!
/*
Code below (just after my cry for help) is MEANT to be buggy.
I mean... "Watcher" threads will try to SYNCH(lock) then WAIT on
"Calculator" when, actually, "Calculator" already has a lock.
"Calculator" is meant to issue a "notify" when there are still no
"Watcher" waiting on it...
So... as long as "Calculator" will never again issue a "notify", "Watcher"
threads are supposed to remain blocked, "waiting" for a never-happening event.
This is exactly what happens when "class Calculator implements Runnable".
But... oddly enough, whenever I make a simple change in "Class Calculator"
code, just making it "extends Thread" instead of "implements Runnable", madness
comes by!!!!!!!!!!!!!!!!
Behavior changes, and , immediately after method "Calculator.run()"
returns, the "c.wait()" code in "Watcher.run()" also returns!! ISN´T THAT
WRONG?
The "c.wait()" call should block forever, shouldn´t it? Boy...
I am by no means a Java Guru... and, in my first contacts with Java threading,
I face such strange stuff. Blessing or a curse?
Anyway... I can´t express myself much better than this. Hope you,
experienced Java folks, have some fun on cracking this (bug?) out.
PS: I am really eagger to receive some replies showing me how wrong
I am, and what I am doing wrong, because I fell hopelessly lost on this matter,
right now.
(e-mail address removed)
(+55) 11 55082813
(+55) 11 55082817
*/
import java.io.*;
public class Reader
{
static String delayDirectory;
static int delayIterations;
public static void main(String argv[]) throws Exception
{
if (argv.length != 2)
{
System.err.println("Usage: java Reader [directory] [iterations]");
return;
}
delayDirectory = argv[0];
delayIterations = Integer.parseInt(argv[1]);
// please, adjust ITERATIONS and DIRECTORY to make delay
//(in Calculator.run()" take a few second... 4 or 5 seconds would
// be great for the purpose of this code-sample.
// PS: Don´t put a "sleep" there... "sleep" would release the
// object-lock, altering the behavior.
Calculator calculator = new Calculator ();
//new Thread(calculator).start();//if Calculator implements Runnable
calculator.start();//if Calculator extends Thread
new Watcher(calculator,"Th A").start();
new Watcher(calculator,"Th B").start();
new Watcher(calculator,"Th C").start();
//add as many of these Watcher-thread instantiations as you please.
}
}
class Watcher extends Thread
{
Calculator c;
String n;
public Watcher(Calculator calc,String nome)
{
c=calc;
n=nome;
}
public void run()
{
try { Thread.sleep((int)(2*1000)); } catch (InterruptedException e) {}
System.out.println(n + " before synchronizing on [Calculator c] object");
synchronized(c) {
try {
System.out.println(n + " Within synch - will Wait for calculation");
c.wait();
System.out.println(n + " WIthin synch - After waiting for calculation");
} catch (InterruptedException e) {}
}
System.out.println(n + " outside synch - Total value is " + c.total);
}
}
class Calculator extends Thread
// switch between "implements Runnable" and "extends Thread" on the line above
// Do not forget to modify function "main" accordingly.
// Do that... and watch strange difference in program behavior!
{
int total;
public void run()
{
System.out.println("Calculator-before synch on Calculator object");
synchronized(this) {
System.out.println("Calculator-within synched code-will calculate");
for (int i=0; i<Reader.delayIterations; i++)
{
total ++;
File f = new File(Reader.delayDirectory);
File fList[] = f.listFiles();
}
System.out.println("Calculator-done calculating... will notify!");
notify();
System.out.println("Calculator-has notified.");
}
System.out.println("Calculator-outside synch-before an arbitrary delay");
for (int i=0; i<Reader.delayIterations; i++)
{
File f = new File(Reader.delayDirectory);
File fList[] = f.listFiles();
}
System.out.println("Calculator-outside synch-after delay- HERE I DIE");
}
}