Download THREAD STATES

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
THREAD STATES
During its lifecycle a thread can move through the following states:
BORN
WAITING
RUNNING
SLEEPING
DEAD
Thread States
State
BORN
RUNNING
DEAD
Description
The thread object has been built but its run method has yet to be started
The run method has been started and is running
The run method has stopped running
SLEEPING
Thread suspends itself for a certain amount of delay time
WAITING
Thread is suspended pending notification or for a delay time
In the original version of Java, methods of the Thread class were provided to transition a thread
through these states.
BORN
t.start( )
t.suspend( )
WAITING
Thread.sleep( m )
RUNNING
t.resume( )
t.stop( )
SLEEPING
m milliseconds
expires
DEAD
Thread States
Page 1
Methods suspend, resume and stop have been deprecated because they are unsafe. I show
you how to safely control a thread’s state in the topic Safe Transitioning of Thread States.
A Demonstration of Thread States
Let’s construct a Java program that demonstrates transitioning a
thread through these five states. For our thread, we use the
Counter class that is explained on pages 3 and 4 of the topic Java
Threads. A Counter object displays a ticking counter as shown to
the right. The class definition is reprinted below.
Counter.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import javax.swing.*;
import java.awt.*;
import javax.swing.border.*;
public class Counter extends Thread
{
private int counter = 0;
// counter to increment
private int delay;
// sleep time
private JTextField display; // display for counter
// fancy JPanel to display, made public so another
// object can add it to a containment hierarchy
public JPanel displayPanel;
public void run( )
// morphed from Thread to do what I want it to.
{
try // needed for call to Thread.sleep (see below)
{
while ( true ) // do forever
{
counter++; // increment counter & display
display.setText( Integer.toString( counter ) );
Thread.sleep( delay ); // sleep
// sleep can throw InterruptedException
}
}
Thread States
Page 2
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
}
catch( InterruptedException e )
{ // probably won't happen, but we handle it anyway
String name = Thread.currentThread().getName();
System.out.println( name + " halted during run." );
return;
}
// end run method
private final int DELAY_RANGE = 2000;
public Counter( String name )
{
super( name ); // call superclass's constructor
// initialize this thread's delay to a random
// integer between a half second and a second
delay = (int)( Math.random( ) * DELAY_RANGE ) + 500;
// initialize the display JTextField
display = new JTextField( 4 );
display.setHorizontalAlignment( JTextField.RIGHT );
display.setEditable( false );
display.setFont(
new Font( "Courier New", Font.BOLD, 72 ) );
display.setBackground ( new Color( 255, 255, 153 ) );
display.setForeground ( new Color( 0, 0, 255 ) );
// create the fancy JPanel
displayPanel = new JPanel( );
displayPanel.setBorder(
new TitledBorder( new EtchedBorder( ), name ) );
// create box with delay label and value
Box delayBox = Box.createVerticalBox( );
delayBox.add( new JLabel( "Delay" ) );
delayBox.add( Box.createVerticalStrut( 5 ) );
delayBox.add(
new JLabel( Integer.toString( delay ) ) );
// add the JTextField and JLabel to the JPanel
displayPanel.add( display );
displayPanel.add( delayBox );
} // end constructor
}
Thread States
Page 3
To control the counter, we create the class ControlPanel
shown below. A ControlPanel object is a JPanel object
containing four buttons arranged in a 2 × 2 grid (see the picture at
right). Its constructor (lines 29–42) creates the button listener,
creates the buttons and builds the grid.
The class constructor creates the buttons by calling method makeButton (see lines 38–41)
whose declaration is on lines 14–27. makeButton is a utility that factors the code for making a
button, adding it to the grid and registering its listener.
ControlPanel has a private inner class StateListener (lines 44–75) that handles user
actions on the buttons. Per the event handling model, StateListener implements the
ActionListener interface by implementing its actionPerformed method, which uses a
cascading if-else statement to determine which button the user has pressed. In response,
actionPerformed calls the appropriate Thread method to transition the counter into the
requested state.
ControlPanel.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class ControlPanel extends JPanel
{
// control buttons
private JButton startBtn, pauseBtn, resumeBtn, quitBtn;
// Counter thread
private Counter counter;
// Listener to the buttons
private StateListener listener;
public JButton makeButton
( String text, Color hue, boolean isOn )
// Make a button with given label, color and enabled.
// Add it to the non-local 'btnGrid'.
// Register the non-local 'listener' as its listener.
{
JButton btn = new JButton( text );
Thread States
Page 4
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
btn.setFont( new Font( "Dialog", Font.BOLD, 32 ) );
btn.setBackground( hue );
btn.setEnabled( isOn );
btn.addActionListener( listener );
this.add( btn ); // add to grid
return btn;
}
public ControlPanel( Counter c )
{
// save Counter thread to instance variable
counter = c;
// change panel layout
setLayout( new GridLayout( 2, 2, 2, 2 ) );
// build listener object
listener = new StateListener( );
// make buttons
startBtn = makeButton( "START", Color.GREEN, true );
pauseBtn = makeButton( "PAUSE", Color.RED, false );
resumeBtn = makeButton( "RESUME", Color.GREEN, false );
quitBtn = makeButton( "QUIT", Color.YELLOW, false );
}
private class StateListener implements ActionListener
{
public void actionPerformed( ActionEvent e )
{ // handle user clicking the buttons
if ( e.getActionCommand( ) == "START" )
{
counter.start( ); // start counter
startBtn.setEnabled( false );
pauseBtn.setEnabled( true );
quitBtn.setEnabled( true );
}
else if ( e.getActionCommand( ) == "PAUSE" )
{
counter.suspend( ); // suspend counter
pauseBtn.setEnabled( false );
resumeBtn.setEnabled( true );
Thread States
Page 5
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
}
}
else if ( e.getActionCommand( ) == "RESUME" )
{
counter.resume( ); // resume counter
pauseBtn.setEnabled( true );
resumeBtn.setEnabled( false );
}
else if ( e.getActionCommand( ) == "QUIT" )
{
counter.stop( ); // stop counter
pauseBtn.setEnabled( false );
resumeBtn.setEnabled( false );
quitBtn.setEnabled( false );
}
} // end actionPerformed
// end StateListener
}
Class UnsafeThreadStates (shown below) is an applet that combines the counter and the
control panel into an executable Java program. It builds the counter at line 14 and the control
panel at line 16, passing the counter to the control panel’s constructor. The counter’s display and
the control panel are added to the applet’s containment hierarchy at lines 18 and 19.
UnsafeThreadStates.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import javax.swing.*;
import java.awt.*;
public class UnsafeThreadStates extends JApplet
{
// Counter thread
private Counter counter;
// Control panel for the thread
private ControlPanel control;
public void init( )
{
// build new thread object, will be in BORN state
counter = new Counter( "Counter 1" );
Thread States
Page 6
15
16
17
18
19
20
21
}
// build control panel sending it the counter
control = new ControlPanel( counter );
// add components to GUI
add( counter.displayPanel, BorderLayout.WEST );
add( control, BorderLayout.CENTER );
// end init method
}
When the applet executes line 14, the counter is placed into the BORN state. The GUI appears
as:
Only the START button is enabled. The user clicks it to transition the counter to the RUNNING
state. This is implemented by the listener’s actionPerformed method calling
counter.start (see ControlPanel.java line 50).
The user transitions the counter between the RUNNING and WAITING states by alternate clicks
of PAUSE and RESUME. These are implemented by the listener’s actionPerformed
method calling counter.suspend and counter.resume (see ControlPanel.java
lines 57 and 63).
Thread States
Page 7
The user transitions the counter to the DEAD state by clicking QUIT; implemented by the
listener’s actionPerformed method calling counter.stop (see ControlPanel.java
line 69).
A thread can only be transitioned to the SLEEPING state by itself.
Safety Issues
Method stop has been deprecated because it can leave objects in an inconsistent state. When a
thread is stopped, it automatically releases all the intrinsic locks that it holds. If the thread held a
lock so that it could atomically update a shared object, then this could potentially leave the
update only partially done.
Methods suspend and resume can cause deadlock. Suppose thread A is suspended when it
holds a lock on some object O; A is waiting for thread B to resume it. One problem arises in that
no other thread can access O while A is suspended. A worse problem arises if B tries to
synchronize on O before resuming A. This causes B to be suspended by the JVM pending release
of the lock. The result: A and B are both suspended, the lock on O will never be released,
deadlock has occurred.
Because of these safety issues, use of these three methods is not recommended for commercialgrade software.
Thread States
Page 8