/**
* Sandeep Desai s_desai@hotmail.com http://www.thedesai.net
*
* JavaThreads.java
*
* You can print this program and read it from top to bottom
*
* Book Reference: Thinking in Java 3rd Ed
*/
import java.util.*;
/**
* One Call stack per thread
* Threads run in any order for a given priority
* Each thread will start and run to completion
* Thread execution order and duration not gauranteed
* once thread is dead it cannot be restarted
* longest waiting thread may not get lock
* JVM has its own thread scheduler,
*
*
* java.lang.Thread methods
* // default name is Thread-0 and so on
* // main thread called main
* Thread(String name)
* Thread(Runnable target)
* Thread(Runnable target, String name)
*
* Thread(ThreadGroup group, String name)
* Thread(ThreadGroup group, Runnable target)
* Thread(ThreadGroup group, Runnable target, String name)
*
* start(), run(), isAlive(), setName(String name), getName()
* setPriority(int priority) // IllegalArgumentException at runtime if > 10
* // JVM does not gaurantee setPriority
* getPriority()
* join() throws InterruptedException,
* join(long milliseconds) throws InterruptedException,
* join(int nanos) throws InterruptedException,
* boolean isAlive() // false for new thread and dead thread
* // true running state only
* void setDaemon(boolean b) // can only be set before start()
* // program runs till all daemon threads finished
* // (main thread can finish first)
* static boolean holdsLock(Object obj) // true if current thread holds lock
* static sleep(long milliseconds) throws InterruptedException,
* static sleep(long milliseconds, int nanos) throws InterruptedException,
* static yield()
* static int MIN_PRIORITY = 1 // setPriority(int)
* static int MAX_PRIORITY = 10
* static int NORM_PRIORITY = 5
*
* java.lang.Object
* wait(), throws InterruptedException, // releases locks
* wait(long timeout), wait(long timeout, int nanos)
* notify(), throws IllegalMonitorException (Runtime Exception)
* notifyAll() throws IllegalMonitorException (Runtime Exception)
* wait, notify must be called from syncrhonized code
*
* wait() gives up lock
* notify(), join(), sleep(), yield() keep locks
*
* java.lang.Runnable { public void run() }
*
* To create thread extend Thread or Runnable
* extending Runnable better approach
* **********
* synchronized only on method or block of code
* synchronized on method does a lock on this so if thread in one syncrhonized
* method, no thread will enter another syncrhonized method
* syncrhonized on static method does lock on object.class
* syncrhonized(null) nullpointer exception thrown
* synchronized can be added or removed when overriding methods
*
* Thread States
*
* Waiting/Blocking/Sleeping
* | ^
* V |
* New -> Runnable -> Running -> Dead
*
* Runnable means start() has been called but thread is not yet
* in the run() method
* It is waiting for the scheduler
*
*
* when Thread.start() overridden Thread won't run unless super.start() called
* Thread.setDaemon() can only be called before start()
* Thread.setPriority() throws runtime exception if priority greater than MAX_PRIORITY
* ThreadGroup can have common priority
*/
class JavaThreads {
static class MyRunnable implements Runnable {
public void run() {
System.out.println("Thread1 (MyRunnable) thread started");
for (int i = 0; i < 5; i++) {
try { Thread.sleep(1000); } catch (InterruptedException e) {}
System.out.println("Thread1 running=" + i);
}
System.out.println("Thread1 over");
}
}
static class MyThread extends Thread {
Thread t;
public MyThread(Thread t) { this.t = t; }
public void run() {
System.out.println("Thread2 started");
doSomething();
// give another thread chance to run,
// Scheduler may end up scheduling this thread itself
yield();
System.out.println("Waiting for thread1 to finish by calling join()");
// locks current thread until t finishes
try {
// can also call t.join(int) which will give up after
// specified number of miliseconds
t.join();
} catch (InterruptedException e) {}
doSomething();
// We wait for t to finish
System.out.println("Thread2 over, CurrentThread="
+ Thread.currentThread().getName());
}
// method will be executed by only one thread at a time
// locks on this
synchronized void doSomething() {
// After sleep thread goes to Runnable state
try { Thread.sleep(100); } catch (InterruptedException e) {}
}
// locks on MyThread.class
static synchronized void doSomething2() {
// After sleep thread goes to Runnable state
try { Thread.sleep(100); } catch (InterruptedException e) {}
}
String s1 = "foo";
String s2 = "foo";
void doSomething3() {
// lock on s only one thread will enter this code at a time
synchronized(s1) {
}
}
// This code will deadlock, which can happend any time
// very hard to debug
void deadlock1() {
// lock on s only one thread will enter this code at a time
synchronized(s1) {
synchronized(s2) {
}
}
}
void deadlock2() {
// lock on s only one thread will enter this code at a time
synchronized(s2) {
synchronized(s1) {
}
}
}
}
static void thread1() {
MyRunnable mr1 = new MyRunnable();
//mr1.run(); // Legal call does not start therad
Thread mt2 = new Thread(mr1);
// setPriority not gauranteed
mt2.setPriority(8); // between 1 to 10 (MIN_PRIORITY to MAX_PRIORITY)
// IllegalArgumentException at runtime
//mt2.setPriority(Thread.MAX_PRIORITY + 2);
mt2.start();
MyThread mt1 = new MyThread(mt2);
mt1.start();
}
static class Thread3 extends Thread {
int total;
String s = "foo";
public void run() {
synchronized(this) {
for (int i=0; i < 30; i++) {
total += i;
try { sleep(100); } catch (InterruptedException e) {}
}
notify();
// this line will throw IllegalMonitorException since
// we are not locked on s
// s.notify();
System.out.println(
new Date() + " Thread3 over notify() all threads waiting on lock");
}
}
}
static void thread2() {
Thread3 t = new Thread3();
t.start();
synchronized(t) {
try {
System.out.println(new Date() + " Wating for t to complete ");
t.wait(); // this should wait approx 3 seconds
} catch (InterruptedException e) {}
System.out.println("Total is->" + t.total);
}
}
static void thread3() {
final SyncTest s = new SyncTest();
Thread t1 = new Thread(new Runnable() {
public void run() {
s.method1();
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
s.method2();
}
});
t1.start();
t2.start();
}
public static void main(String[] args) {
thread2();
thread1();
thread3();
Consumer.test();
}
}
class SyncTest {
public synchronized void method1() {
for (int i = 0; i < 4; ++i) {
try {
Thread.sleep(1000);
System.out.println("method1");
} catch (InterruptedException e) {}
}
}
public static synchronized void method2() {
for (int i = 0; i < 4; ++i) {
try {
Thread.sleep(1000);
System.out.println("method2");
} catch (InterruptedException e) {}
}
}
}
class Producer extends Thread {
static final int MAXQUEUE = 3;
private Vector messages = new Vector();
public void run() {
try {
while (true) {
putMessage();
sleep(1000);
}
}
catch( InterruptedException e ) { }
}
private synchronized void putMessage()
throws InterruptedException {
while ( messages.size() == MAXQUEUE ) {
System.out.println("waiting in Producer.putMessage() as messages queue full");
wait();
}
messages.addElement( new java.util.Date().toString() );
System.out.println("notifying threads waiting on producer");
notify();
}
// Called by Consumer
public synchronized String getMessage()
throws InterruptedException {
System.out.println("notifying producer to wakeup");
notify();
while ( messages.size() == 0 ) {
System.out.println("waiting in Producer.getMessage() as messages queue empty");
wait();
}
String message = (String)messages.firstElement();
messages.removeElement( message );
return message;
}
}
class Consumer extends Thread {
Producer producer;
Consumer(Producer p) { producer = p; }
public void run() {
try {
for (int i =0; i < 20; ++i) {
String message = producer.getMessage();
System.out.println("Consumer.run(): Got message: " + message);
sleep( 2000 );
}
}
catch( InterruptedException e ) { }
}
public static void test() {
Producer producer = new Producer();
producer.start();
new Consumer( producer ).start();
}
}