Threads

From Suhrid.net Wiki
Revision as of 01:05, 11 June 2011 by Suhridk (talk | contribs)
Jump to navigationJump to search
  • Think of Thread as the "worker" and Runnable as the job.
  • Define work to be done in a class that implements Runnable.
  • Instantiate the thread using the runnable object. (Thread is in the new state)
  • Then start() it. (Thread moves to the runnable state, eligible to run, perhaps waiting for the scheduler to run it)
class Job implements Runnable {
     public void run() {
         //work to be performed in  a separate thread.
     }
}

Job j = new Job();
Thread t = new Thread(j);
t.start();
  • When thread actually runs it is in the running state.
  • The thread can also go into waiting/blocked/sleeping state. e.g. waiting for an IO Resource such as a packet to arrive. In other words it is NOT runnable.
  • Once run() completes the Thread goes to the dead state. You cannot call start() again on it. Of course, the thread object itself can still be used.

SLEEP

  • Be careful of the Thread classes static methods such as sleep() and yield(). They refer to the current executing thread! Do not be misled when they are invoked using a thread object.
  • e.g. t1.sleep() will not cause Thread t1 to sleep(), it causes the current executing thread to sleep().
  • sleep() specifies that the Thread must go to sleep for at least the specified duration.
  • What does this mean, it means that when the sleep duration expires and thread wakes up, the thread immediately does not go to running - it goes to the runnable state.
  • so sleep() gives the minimum duration that the thread will not run. You cannot use it as an accurate timer!

JOIN

  • t.join() will take the current thread from which this code is called and join it to the end of t.
  • This means the thread from which join() is called will wait until t finishes before it runs again.


Synchronization

  • Control access to shared object by multiple threads.
  • Only methods and code blocks can be synchronized.
  • Synchronization happens through object locks.
  • Suppose a synchronized method is called, then the lock of the object that invoked the method is used for synchronization.
  • When a thread enters a synchronized method, since an object has only one lock - even other synchronized methods in the class cannot be entered for that object by other threads.
  • The following program invokes three threads to each print a single different letter 100 times.
  • If the code is not synchronized, different threads can print the same letter - because they would start printing before the letter has got a chance to change.
  • Note that printLetter() is not synchronized. Why ? Because printLetter is invoked using a LetterPrintJob object and each thread uses a separate LetterPrintJob object.
  • So you have to synchronize on the lock of the shared object which in this case is the StringBuffer.
class LetterPrintJob implements Runnable {

	private StringBuffer strBuf;

	LetterPrintJob(StringBuffer strBuf) {
		this.strBuf = strBuf;
	}

	@Override
	public void run() {
		printLetter();
	}

	void printLetter() {
		synchronized(strBuf) {
			char letter = strBuf.charAt(0);
			for(int i=0; i < 100; i++) {
				System.out.println(Thread.currentThread().getName() + ":" + letter);
			}
			strBuf.setCharAt(0, ++letter);
		}
	}
}

public class SynchroTest {

	public static void main(String[] args) {
		StringBuffer strBuf = new StringBuffer("A");
		new Thread(new LetterPrintJob(strBuf),"T1").start();
		new Thread(new LetterPrintJob(strBuf),"T2").start();
		new Thread(new LetterPrintJob(strBuf),"T3").start();
	}

}


  • Since each thread has its own stack, two threads executing the same method concurrently will use different copies of local variables.