Course List: http://www.c-jump.com/bcc/
Classes Thread and Runnable create a new thread of execution
Thread's interrupt() method and the InterruptedException allow thread to
switch from current work to another method
it's very common to terminate the thread during the interrupt
The synchronized keyword prevents multiple threads to run a particular method concurrently
This allows to serialize access to the same data from multiple threads
Object.wait() method puts the thread to sleep:
until interrupt (described above), or
until another thread calls notifyAll()
The difference between a program that runs in a single or multiple threads...
Further highly recommended reading:
Introduction to Java Concurrency by Jakob Jenkov
Java Concurrency Tutorial Lesson by oracle.com
Java Concurrency in Swing Tutorial Lesson by oracle.com
Threading with Swing and SwingUtilities.invokeLater() by javamex.com
To improve the performance of applications with extensive I/O operations
To improve the responsiveness of GUI applications
To allow two or more users to run server-based applications simultaneously
Classes and interfaces used to create threads:
Key methods of the Thread class, Runnable interface, and the Object class:
Thread.start() // JVM calls the run() method of the thread Runnable.run() // top-level entry into a thread Thread.run() Thread.sleep() // sleep for the specified number of milliseconds. // Calls from within a synchronized block - MANDATORY! Object.wait() // wait until someone calls notify() on this object Object.notify() // wake up objects that waits Object.notifyAll()
Common pitfalls:
calling run() instead of start()
calling Object's wait() notify() notifyAll() from an un-synchronized code. Note: IllegalMonitorStateException will be thrown.
calling Swing code directly from the main application startup thread. This must be done on Swing's event dispatch thread via SwingUtilities.invokeLater()
Inherit the Thread class
Implement the Runnable interface, then
pass a reference to the Runnable object to the constructor of the Thread class.
This is useful if the thread needs to inherit a class other than the Thread class.
New
Runnable
Blocked
Waiting
Terminated
java.lang.Thread;
Common constructors of the Thread class:
Thread() Thread( String name ) Thread( Runnable obj ) Thread( Runnable obj, String name )
run() // top entry point into the thread - called by start() - not you!
start() // schedules the thread for execution
getName() // returns thread name
currentThread() // returns the thread object for current thread
setDaemon( boolean ) // daemon thread runs in background, e.g. garbage collection
sleep( long ) // pauses current thread for a given period of milliseconds
interrupt() // wake-up signal to sleeping or waiting thread
isInterrupted() // manual check for a wake-up signal
yield() // similar to sleep( 0 )
A procedure for creating a thread from the Thread class
Create a class that inherits the Thread class.
Override the run() method to perform the desired task.
Create the thread by instantiating an object from the class.
Call the start method of the thread object.
public class Main { public static void main(String[] args) { Thread ct = Thread.currentThread(); System.out.println( ct.getName() + " started" ); // create the IO thread Thread worker = new IOThread(); // start the IO thread worker.start(); System.out.println( ct.getName() + " started " + worker.getName() ); System.out.println( ct.getName() + " finished" ); } }//class Main
public class IOThread extends Thread
{
@Override
public void run()
{
System.out.println( this.getName() + " started" );
try
{
// Sleep for 2 seconds to simulate an IO task
// that takes a long time
Thread.sleep( 2000 );
}
catch( InterruptedException ex )
{
}
System.out.println( this.getName() + " finished" );
}
}
main started main starts Thread-0 main finished Thread-0 started Thread-0 finished
Create a class that implements the Runnable interface.
Implement the run() method to perform the desired task.
Create the thread by supplying an instance of the Runnable class to the Thread constructor.
Call the start() method of the thread object.
public class IOTask implements Runnable
{
@Override
public void run()
{
Thread ct = Thread.currentThread();
System.out.println( ct.getName() + " started" );
try
{
// Sleep for 2 seconds to simulate an IO task
// that takes a long time
Thread.sleep( 2000 );
}
catch( InterruptedException ex )
{
}
System.out.println( ct.getName() + " finished" );
}
}
public class Main { public static void main(String[] args) { Thread ct = Thread.currentThread(); System.out.println(ct.getName() + " started."); // create the new thread Thread worker = new Thread( new IOTask() ); // start the new thread worker.start(); System.out.println(ct.getName() + " starts " + worker.getName() + "."); System.out.println(ct.getName() + " finished."); } }//class Main
The CPU automatically interrupts itself all the time to implement the OS thread scheduler
The Java interruption mechanism wakes up a waiting or sleeping thread
If the interrupted thread is not in a blocking call, then:
(a) interrupt() sets the interrupted flag
(b) as soon as the thread makes a blocking call such as Thread.sleep(), InterruptedException is thrown immediately
The InterruptedException is thrown when another thread interrupts the thread calling the blocking method
Aa s general rule of thumb, an InterruptedException should cause the overall task of the thread to be cancelled
It's generally best to set the thread's interrupted status again:
public class MyRunnable implements Runnable() {
public void run() {
try {
doSomeWork();
} catch ( InterruptedException iex ) {
}
}
private void doSomeWork()
{
try {
// do the work
} catch ( InterruptedException iex ) {
// We've been already interrupted here, but let
// the caller deal with it. To r re-throw the exception, we call
Thread.currentThread().interrupt();
// which sets the interrupt flag and re-throws the InterruptedException
}
}
}//class MyRunnable
Calling
Thread.currentThread().interrupt();
sets the interrupt flag of the current thread and will reraise the InterruptedException on it again. The caller of doSomeWork() the also gets a chance to examine the InterruptedException.
Thus,
Thread.currentThread().interrupt();
is a better alternative to simply re-throwing the InterruptedException, because it preserves the interrupted state of the current thread.
Interrupts are very effective way to cancel tasks
If the interrupted method is not calling a blocking method like like sleep() or wait(), then
interrupt() will not automatically interrupt the thread
To manually check for the interrupted flag, the thread should call isInterrupted():
try { while ( true ) { // do some work... if ( Thread.interrupted() ) { throw new InterruptedException(); } } } catch ( InterruptedException iex ) { // We've been interrupted: Thread.currentThread().interrupt(); return; }
import java.util.Scanner; public class Main { public static void main(String[] args) { System.out.println( "Press the Enter key to stop counting:" ); Thread counter = new Thread( new Counter() ); // start the counter thread counter.start(); Scanner sc = new Scanner( System.in ); String str = "start"; // wait for the user to press Enter while ( !str.equals("") ) { str = sc.nextLine(); } // interrupt the counter thread counter.interrupt(); } }//class Main
public class Counter implements Runnable
{
@Override
public void run()
{
Thread ct = Thread.currentThread();
int count = 1;
while ( !ct.isInterrupted() )
{
System.out.println(
ct.getName() + " count " + count );
count++;
try
{
// Sleep for 1 second
Thread.sleep( 1000 );
}
catch( InterruptedException e )
{
break;
}
}
System.out.println( ct.getName() + " got interrupted" );
}
}//class Counter
Press the Enter key to stop counting: Thread-0 count 1 Thread-0 count 2 Thread-0 count 3 Thread-0 got interrupted
The synchronized keyword can be used to mark four different types of blocks:
Instance methods
Static methods
Code blocks inside instance methods
Code blocks inside static methods
The idea: When one thread is executing a synchronized method, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.
public class SynchronizedCounter { private int value = 0; public synchronized void increment() { ++value; } public synchronized void decrement() { --value; } public synchronized int getValue() { return value; } }//class SynchronizedCounter
public|private synchronized returnType methodName(
[parameterList])
{
statements
}
public synchronized int getInvoiceNumber()
{
return invoiceNumber++;
}
public void add( int value )
{
Thread ct = Thread.currentThread();
synchronized( ct )
{
// Inside critical section:
count += value;
}
}
For a complete program using synchronized blocks of code, see multithreading examples on CIS-257 samples page.
wait() notify() notifyAll()
Code that waits on a condition:
// if there are no orders ready, wait while ( orderQueue.count() == 0 ) { try { wait(); } catch ( InterruptedException e ) { } }
Another thread satisfies the condition and notifies other threads:
// add an order to the queue orderQueue.add( order ); // notify other threads notifyAll();
boolean taken = false; public synchronized void grab() throws InterruptedException { while ( taken ) { wait(); // wait unti my turn } taken = true; // okay, my turn! } public synchronized void drop() { taken = false; notifyAll() // wake up all waiting threads } // Client code: resource.grab(); // Critical section: do something with the resource resource.drop();
setPriority( int )
Fields of the Thread class used to set thread priorities:
MAX_PRIORITY MIN_PRIORITY NORM_PRIORITY
public class Main { public static void main( String[] args ) { Thread worker = new Thread( new IOTask() ); worker.setPriority( Thread.MIN_PRIORITY ); worker.start(); //... } }//class Main
The the Order Queue application demonstrates the producer/consumer design pattern for concurrency control:
Starting the order queue. Starting 3 order taker threads, each producing 3 orders. Starting 2 order handler threads. OrderTaker threads OrderHandler threads ============================ ============================= Order #1 created by Thread-1 Order #2 created by Thread-2 Order #1 processed by Thread-3 Order #2 processed by Thread-4 Order #3 created by Thread-0 Order #4 created by Thread-1 Order #5 created by Thread-2 Order #6 created by Thread-0 Order #3 processed by Thread-3 Order #4 processed by Thread-4 Order #7 created by Thread-1 Order #8 created by Thread-2 Order #9 created by Thread-0 Order #5 processed by Thread-3 Order #6 processed by Thread-4 Order #7 processed by Thread-3 Order #8 processed by Thread-4 Order #9 processed by Thread-3
Order class:
Constructor creates an Order object with a unique order number
toString() method returns a string in the form "Order #n" where n is the order number
OrderQueue -- a thread-safe method-synchronized class
pushOrder( Order ) method adds order to the queue
Order pullOrder() method retrieves the first available order from the queue
OrderTaker -- a worker thread class
Constructor OrderTaker( int orderCount, OrderQueue queue ) takes specified number of orders to be added to the queue
run() adds orders to the queue and displays info about each order added. The thread sleeps for one second between the orders.
OrderHandler -- a worker thread class
Constructor OrderHandler( OrderQueue queue ) creates the order handler and takes reference to the queue
run() retrieves orders from the queue and displayes info for each order retrieved. The thread sleeps for two seconds between the orders.
Sequence diagram for Order Queue calls:
Jakob Jenkov: Java Concurrency / Multithreading
tutorials.jenkov.com/java-concurrency/index.html
Jakob Jenkov: java.util.concurrent - Java 5 Concurrency Utilities
tutorials.jenkov.com/java-util-concurrent/index.html
Oracle tutorial: High Level Concurrency Objects
docs.oracle.com/javase/tutorial/essential/concurrency/highlevel.html