/** * 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(); } }