You are on page 1of 16

Chapter 13: Threads (6 hrs) Chapter Objective: Define a thread Create separate threads in a Java technology program, controlling

ng the code and data that are used by that thread Control the execution of a thread and write platform independent code with threads Describe the difficulties that might arise when multiple threads share data Use wait and notify to communicate between threads Use synchronized to protect data from corruption You are probably familiar with multitasking in your operating system: the ability to have more than one program working at what seems like the same time. For example, you can print while editing or downloading your email. Nowadays, you are likely to have a computer with more than one CPU, but the number of concurrently executing processes is not limited by the number of CPUs. The operating system assigns CPU time slices to each process, giving the impression of parallel activity. Multithreaded programs extend the idea of multitasking by taking it one level lower: individual programs will appear to do multiple tasks at the same time. Each task is usually called a threadwhich is short for thread of control. Programs that can run more than one thread at once are said to be multithreaded. So, what is the difference between multiple processes and multiple threads? The essential difference is that while each process has a complete set of its own variables, threads share the same data. This sounds somewhat risky, and indeed it can be, as you will see later in this chapter. However, shared variables make communication between threads more efficient and easier to program than interprocess communication. Moreover, on some operating systems, threads are more lightweight than processesit takes less overhead to create and destroy individual threads than it does to launch new processes. Multithreading is extremely useful in practice. For example, a browser should be able to simultaneously download multiple images. A web server needs to be able to serve concurrent requests. Graphical user interface (GUI) programs have a separate thread for gathering user interface events from the host operating environment. This chapter shows you how to add multithreading capability to your Java applications. Multithreading changed dramatically in Java SE 5.0, with the addition of a large number of classes and interfaces that provide high-quality implementations of the mechanisms that most application programmers will need. In this chapter, we explain the features that were added to Java SE 5.0 as well as the classic synchronization mechanisms, and help you choose between them. Fair warning: multithreading can get very complex. In this chapter, we cover all the tools that an application programmer is likely to need. However, for more intricate system-level programming, we suggest that you turn to a more advanced reference, such as Java Concurrency in Practice by Brian Goetz (Addison-Wesley Professional, 2006). What Are Threads? Threads are Virtual CPU. It contains three things, the CPU (Thread Class), Code and Data. Let's take a look at this sample code that implements threading without GUI. 1 2 3 4 5 6 // code class HelloRunner implements Runnable { int i; public void run() {
Prepared by: Lawrence G. Decamora III, scjp

Page 1 of 16

7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 data. 31 32

} }

i = 0; while(i < 50) { if(i % 3 == 0) { try { Thread.sleep(500); } catch(InterruptedException ie) {} } System.out.println(++i + " = " + Thread.currentThread().getName()); } System.out.println(Thread.currentThread().getName() + " dies.");

public class ThreadTester { public static void main(String args[]) { // data HelloRunner hr = new HelloRunner(); // cpu Thread t1 = new Thread(hr, "ThreadOne"); Thread t2 = new Thread(hr, "ThreadTwo"); t1.start(); t2.start();

} }

Multithreaded programming creates threads from a Runnable instance which in turn, shares the same // data HelloRunner hr = new HelloRunner(); Declares an instance of HelloRunner object which is an instance from a Runnable instance. 1 2 // code class HelloRunner implements Runnable hr contains an instance variable i. 4 int i;

After which, hr object was passed to the Thread Objects that can share the instance variable i in the HelloRunner object. 34 35 36
Page 2 of 16

// cpu Thread t1 = new Thread(hr, "ThreadOne"); Thread t2 = new Thread(hr, "ThreadTwo");


Prepared by: Lawrence G. Decamora III, scjp

Starting a Thread. The start method places the Thread in a runnable state which in turn executes the run method present. The run method must be present to all class that implements the Runnable interface. 38 39 Thread States. t1.start(); t2.start();

All threads are created. Once created you can call the start method, after this, the thread execution is now out of your hands. The Operating System (OS) scheduler will now take charge of the execution of the thread. This will go on until the run method is running, after which your thread dies. In between the running state of the threads, your running threads may be blocked by the scheduler to enable other threads to run. Terminating a Thread. Terminating a Thread must be done programmatically. Take a look at this sample code: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Runner implements Runnable { private boolean timeToQuit=false; public void run() { while ( ! timeToQuit ) { // continue doing work } // clean up before run() ends public void stopRunning() { timeToQuit=true; } }

Lines 11 to 13 allows you to create a method that stops a thread or that will allow you to jump out of the run method.

Page 3 of 16

Prepared by: Lawrence G. Decamora III, scjp

Threads and GUI. Let us start by looking at a program that does not use multiple threads and that, as a consequence, makes it difficult for the user to perform several tasks with that program. After we dissect it, we then show you how easy it is to have this program run separate threads. This program animates a bouncing ball by continually moving the ball, finding out if it bounces against a wall, and then redrawing it. As soon as you click the Start button, the program launches a ball from the upper-left corner of the screen and the ball begins bouncing. The handler of the Start button calls the addBall method. That method contains a loop running through 1,000 moves. Each call to move moves the ball by a small amount, adjusts the direction if it bounces against a wall, and then redraws the panel. Ball ball = new Ball(); panel.add(ball); for (int i = 1; i <= STEPS; i++) { ball.move(panel.getBounds()); panel.paint(panel.getGraphics()); Thread.sleep(DELAY); } The static sleep method of the Thread class pauses for the given number of milliseconds.

Here's a complete set of codes that will enable a single threaded bouncing ball. // Bounce.java import java.awt.*; import java.awt.event.*; import javax.swing.*; /** * Shows an animated bouncing ball. * @version 1.33 2007-05-17 * @author Cay Horstmann
Page 4 of 16 Prepared by: Lawrence G. Decamora III, scjp

*/ public class Bounce { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { JFrame frame = new BounceFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }); } } /** * The frame with ball component and buttons. */ class BounceFrame extends JFrame { /** * Constructs the frame with the component for showing the bouncing ball and Start and * Close buttons */ public BounceFrame() { setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); setTitle("Bounce"); comp = new BallComponent(); add(comp, BorderLayout.CENTER); JPanel buttonPanel = new JPanel(); addButton(buttonPanel, "Start", new ActionListener() { public void actionPerformed(ActionEvent event) { addBall(); } }); addButton(buttonPanel, "Close", new ActionListener() { public void actionPerformed(ActionEvent event) { System.exit(0); } }); add(buttonPanel, BorderLayout.SOUTH);

/** * Adds a button to a container. * @param c the container * @param title the button title
Page 5 of 16 Prepared by: Lawrence G. Decamora III, scjp

* @param listener the action listener for the button */ public void addButton(Container c, String title, ActionListener listener) { JButton button = new JButton(title); c.add(button); button.addActionListener(listener); } /** * Adds a bouncing ball to the panel and makes it bounce 1,000 times. */ public void addBall() { try { Ball ball = new Ball(); comp.add(ball); for (int i = 1; i <= STEPS; i++) { ball.move(comp.getBounds()); comp.paint(comp.getGraphics()); Thread.sleep(DELAY); } } catch (InterruptedException e) { } } private BallComponent comp; public static final int DEFAULT_WIDTH = 450; public static final int DEFAULT_HEIGHT = 350; public static final int STEPS = 1000; public static final int DELAY = 3;

//Ball.java import java.awt.geom.*; /** * A ball that moves and bounces off the edges of a rectangle * @version 1.33 2007-05-17 * @author Cay Horstmann */ public class Ball { /** * Moves the ball to the next position, reversing direction if it hits one of the edges */ public void move(Rectangle2D bounds) { x += dx; y += dy; if (x < bounds.getMinX())
Page 6 of 16 Prepared by: Lawrence G. Decamora III, scjp

} if (x + XSIZE >= bounds.getMaxX()) { x = bounds.getMaxX() - XSIZE; dx = -dx; } if (y < bounds.getMinY()) { y = bounds.getMinY(); dy = -dy; } if (y + YSIZE >= bounds.getMaxY()) { y = bounds.getMaxY() - YSIZE; dy = -dy; }

x = bounds.getMinX(); dx = -dx;

/** * Gets the shape of the ball at its current position. */ public Ellipse2D getShape() { return new Ellipse2D.Double(x, y, XSIZE, YSIZE); } private private private private private private } // BallComponent.java import java.awt.*; import java.util.*; import javax.swing.*; /** * The component that draws the balls. * @version 1.33 2007-05-17 * @author Cay Horstmann */ public class BallComponent extends JPanel { /** * Add a ball to the component. * @param b the ball to add */ public void add(Ball b) { balls.add(b); }
Page 7 of 16 Prepared by: Lawrence G. Decamora III, scjp

static static double double double double

final int XSIZE = 15; final int YSIZE = 15; x = 0; y = 0; dx = 1; dy = 1;

public void paintComponent(Graphics g) { super.paintComponent(g); // erase background Graphics2D g2 = (Graphics2D) g; for (Ball b : balls) { g2.fill(b.getShape()); } } private ArrayList<Ball> balls = new ArrayList<Ball>(); } Using Threads to give others a chance. We will make our bouncing-ball program more responsive by running the code that moves the ball in a separate thread. In fact, you will be able to launch multiple balls. Each of them is moved by its own thread. In addition, the AWT event dispatch thread continues running in parallel, taking care of user interface events. Because each thread gets a chance to run, the event dispatch thread has the opportunity to notice when a user clicks the Close button while the balls are bouncing. The thread can then process the close action. We use ball-bouncing code as an example to give you a visual impression of the need for concurrency. In general, you will always want to be wary of any long-running computation. Your computation is likely to be a part of some bigger framework, such as a GUI or web framework. Whenever the framework calls one of your methods, there is usually an expectation of a quick return. If you need to do any task that takes a long time, you should use a separate thread. Here is a simple procedure for running a task in a separate thread: 1. Place the code for the task into the run method of a class that implements the Runnable interface. That interface is very simple, with a single method: public interface Runnable { void run(); } You simply implement a class, like this: class MyRunnable implements Runnable { public void run() { // task code } } 2. Construct an object of your class: Runnable r = new MyRunnable(); 3. Construct a Thread object from the Runnable: Thread t = new Thread(r); 4. Start the thread: t.start(); To make our bouncing-ball program into a separate thread, we need only implement a class BallRunnable
Page 8 of 16 Prepared by: Lawrence G. Decamora III, scjp

and place the code for the animation inside the run method, as in the following code: class BallRunnable implements Runnable { . . . public void run() { try { for (int i = 1; i <= STEPS; i++) { ball.move(component.getBounds()); component.repaint(); Thread.sleep(DELAY); } } catch (InterruptedException exception) { } } . . . } Again, we need to catch an InterruptedException that the sleep method threatens to throw. We discuss this exception in the next section. Typically, interruption is used to request that a thread terminates. Accordingly, our run method exits when an InterruptedException occurs. Whenever the Start button is clicked, the addBall method launches a new thread. Ball b = new Ball(); panel.add(b); Runnable r = new BallRunnable(b, panel); Thread t = new Thread(r); t.start();

Thats all there is to it! You now know how to run tasks in parallel. The remainder of this chapter tells you how to control the interaction between threads. In the next section, you will see a complete listing of Java Codes that will enable you to see and run the Multithreaded Bouncing Ball.
Page 9 of 16 Prepared by: Lawrence G. Decamora III, scjp

//BounceThread.java import java.awt.*; import java.awt.event.*; import javax.swing.*; /** * Shows animated bouncing balls. * @version 1.33 2007-05-17 * @author Cay Horstmann */ public class BounceThread { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { JFrame frame = new BounceFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }); } } /** * A runnable that animates a bouncing ball. */ class BallRunnable implements Runnable { /** * Constructs the runnable. * @aBall the ball to bounce * @aPanel the component in which the ball bounces */ public BallRunnable(Ball aBall, Component aComponent) { ball = aBall; component = aComponent; } public void run() { try { for (int i = 1; i <= STEPS; i++) { ball.move(component.getBounds()); component.repaint(); Thread.sleep(DELAY); } } catch (InterruptedException e) { } }
Page 10 of 16 Prepared by: Lawrence G. Decamora III, scjp

private Ball ball; private Component component; public static final int STEPS = 1000; public static final int DELAY = 5;

/** * The frame with panel and buttons. */ class BounceFrame extends JFrame { /** * Constructs the frame with the component for showing the bouncing ball and Start and * Close buttons */ public BounceFrame() { setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); setTitle("BounceThread"); comp = new BallComponent(); add(comp, BorderLayout.CENTER); JPanel buttonPanel = new JPanel(); addButton(buttonPanel, "Start", new ActionListener() { public void actionPerformed(ActionEvent event) { addBall(); } }); addButton(buttonPanel, "Close", new ActionListener() { public void actionPerformed(ActionEvent event) { System.exit(0); } }); add(buttonPanel, BorderLayout.SOUTH);

} /** * Adds a button to a container. * @param c the container * @param title the button title * @param listener the action listener for the button */ public void addButton(Container c, String title, ActionListener listener) { JButton button = new JButton(title); c.add(button); button.addActionListener(listener); } /** * Adds a bouncing ball to the canvas and starts a thread to make it bounce
Page 11 of 16 Prepared by: Lawrence G. Decamora III, scjp

*/

public void addBall() { Ball b = new Ball(); comp.add(b); Runnable r = new BallRunnable(b, comp); Thread t = new Thread(r); t.start(); } private BallComponent comp; public static final int DEFAULT_WIDTH = 450; public static final int DEFAULT_HEIGHT = 350; public static final int STEPS = 1000; public static final int DELAY = 3;

//Ball.java import java.awt.geom.*; /** * A ball that moves and bounces off the edges of a rectangle * @version 1.33 2007-05-17 * @author Cay Horstmann */ public class Ball { /** * Moves the ball to the next position, reversing direction if it hits one of the edges */ public void move(Rectangle2D bounds) { x += dx; y += dy; if (x < bounds.getMinX()) { x = bounds.getMinX(); dx = -dx; } if (x + XSIZE >= bounds.getMaxX()) { x = bounds.getMaxX() - XSIZE; dx = -dx; } if (y < bounds.getMinY()) { y = bounds.getMinY(); dy = -dy; } if (y + YSIZE >= bounds.getMaxY()) { y = bounds.getMaxY() - YSIZE; dy = -dy; } }

Page 12 of 16

Prepared by: Lawrence G. Decamora III, scjp

/** * Gets the shape of the ball at its current position. */ public Ellipse2D getShape() { return new Ellipse2D.Double(x, y, XSIZE, YSIZE); } private private private private private private } //BallComponent.java import java.awt.*; import java.util.*; import javax.swing.*; /** * The component that draws the balls. * @version 1.33 2007-05-17 * @author Cay Horstmann */ public class BallComponent extends JPanel { /** * Add a ball to the component. * @param b the ball to add */ public void add(Ball b) { balls.add(b); } public void paintComponent(Graphics g) { super.paintComponent(g); // erase background Graphics2D g2 = (Graphics2D) g; for (Ball b : balls) { g2.fill(b.getShape()); } } } private ArrayList<Ball> balls = new ArrayList<Ball>(); static static double double double double final int XSIZE = 15; final int YSIZE = 15; x = 0; y = 0; dx = 1; dy = 1;

Other ways to create a Thread. 1. implements the Runnable interface: - Better object-oriented design - Single Inheritance issue is addressed - Consistency 2. Extends the class Thread. Simpler Code
Page 13 of 16 Prepared by: Lawrence G. Decamora III, scjp

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

public class MyThread extends Thread { public void run() { while ( true ) { // do lots of interesting stuff try { Thread.sleep(100); } catch (InterruptedException e) { // sleep interrupted } } } public static void main(String args[]) { Thread t = new MyThread(); t.start(); } }

The synchronized keyword. Every Java object has a lock. A thread can acquire the lock by calling a synchronized method. There are two ways on how to use the synchronized code block: public void withDraw(char c) { synchronized(this) { // The push method code } } or... public synchronized void push(char c) { // The push method code } There is a second mechanism for acquiring the lock, by entering a synchronized block. When a thread enters a block of the form synchronized (obj) // this is the syntax for a synchronized block { critical section } then it acquires the lock for obj. You will sometimes find ad hoc locks, such as public class Bank { public void transfer(int from, int to, int amount) { synchronized (this) // an ad-hoc lock { accounts[from] -= amount; accounts[to] += amount; } System.out.println(. . .);
Page 14 of 16 Prepared by: Lawrence G. Decamora III, scjp

} . . . private double[] accounts; private Object lock = new Object(); } Here, the lock object is created only to use the lock that every Java object possesses. Sometimes, programmers use the lock of an object to implement additional atomic operations, a practice known as clientside locking. Here's the State Diagram with Synchronization:

The Monitor Model for Synchronization. Locks and conditions are powerful tools for thread synchronization, but they are not very object oriented. For many years, researchers have looked for ways to make multithreading safe without forcing programmers to think about explicit locks. One of the most successful solutions is the monitor concept that was pioneered by Per Brinch Hansen and Tony Hoare in the 1970s. In the terminology of Java, a monitor has these properties:

A monitor is a class with only private fields. Each object of that class has an associated lock. All methods are locked by that lock. In other words, if a client calls obj.method(), then the lock for obj is automatically acquired at the beginning of the method call and relinquished when the method returns. Because all fields are private, this arrangement ensures that no thread can access the fields while another thread manipulates them. The lock can have any number of associated conditions.

Earlier versions of monitors had a single condition, with a rather elegant syntax. You can simply call await accounts[from] >= balance without using an explicit condition variable. However, research showed that indiscriminate retesting of conditions can be inefficient. This problem is solved with explicit condition variables, each managing a separate set of threads. The Java designers loosely adapted the monitor concept. Every object in Java has an intrinsic lock and an intrinsic condition. If a method is declared with the synchronized keyword, then it acts like a monitor method. The condition variable is accessed by calling wait/notifyAll/notify.

Page 15 of 16

Prepared by: Lawrence G. Decamora III, scjp

Here's a Thread State Diagram with wait and notify.

Page 16 of 16

Prepared by: Lawrence G. Decamora III, scjp