Basics Of Thread Programming –
Part 3
Introduction
to Java Thread Programming
Java language is well designed keeping in mind the thread related semantics.
Every Java object has it's monitor, which will be obtained by the thread
to lock it. Java offers the thread support in an object oriented fashion
and its threading model is directly related to the native operating system's
threading model. But on non-multithreaded environments, Java Virtual Machines
are implemented to simulate the threads by JVM, and these threads are called
green threads. So a java program may work different on different platforms
depending on the threading features of those platforms.
Here are the most important features of java threads.
- Threads are to be created subclassing the java.lang.Thread class
or implementing java.lang.Runnable interface.
- Thread will be represented and controlled by object of Thread subclass
or Runnable interface implementation class.
- Runnable interface has standardized the methods for thread programming.
So they have to be overloaded in the implementation classes. Since Thread
class implements Runnable interface, methods of Thread class are to be overridden.
Implementing/Overriding run method is mandatory. Rest of the methods
can be implemented/overridden optionally.
- Runnable interface is of great use when a thread class has to be
a subclass of some other class, because multiple inheritance is not allowed
in Java. Thread class can implement Runnable interface and can be derived
from any other class.
- Threads can be accessed/controlled directly with the thread object
methods or some static methods of Thread class.
- Threads can be named and their operational parameters like priority
etc can be set.
- Threads can be tied into a ThreadGroup where a collection of treads
can be manipulated at once, instead of working with all of the threads individually.
- Threads can be in one of the following states
- Created: Thread object is just created and thread has not started
running
- Running: Thread is in active state where its code is being executed
- Sleeping: Thread is in non active state where its code is not
being executed
- Suspended: Threads execution is suspended, but methods related
to this are deprecated due to a chance of some potential problems. Making
the thread to wait for some lock or event can simulate the thread suspension.
- Resumed: Threads execution is restarted after suspension, but
this method is deprecated due to a chance of some potential problems. Making
the thread to wait for some lock or event and then giving them the lock
or event can simulate this.
- Stopped: Thread has completed the work it has to do. But the
thread object still lives depending on the references to it.
- Destroyed: Thread object is garbage collected or destroyed completely.
Following sections explain different concepts of thread lifecycle management
and related APIs for programming the threads. While explaining the concepts
only incomplete code pieces relevant to the context are shown. Complete
source code of the sample is available for download from the website. There
may be minor differences between the code snippets and the complete source
code at the website. It is made for making the illustration more effective.
Thread Creation
Creation of threads in Java is to be done by creating the Thread class
object. It can be done in two ways.
Create Subclass of java.lang.Thread
Create a subclass or derived class of java.lang.Thread class and instantiate
it. Overload the run() method of Thread class with the code that has to
be executed by the thread.
public class MyThread extends Thread
{
// MyThread’s data and methods
……………………..
public void run() {
//
code for executing the tasks the thread has to perform
}
}
……………………………
……………………………
// create a thread and let it be in created state
Thread thread1 = new MyThread(…………);
.............................
Implement java.lang.Runnable Interface
Implement the java.lang.Runnable interface to make a thread class, create
an object of it and create an instance of java.lang.Thread class with
Runnable implemented object passed as constructor parameter. Overload the
run method of Runnable interface with the code that has to be executed by
the thread.
public class MyRunnable implements Runnable
{
// MyRunnable’s data and methods
……………………..
public void run() {
//
code for executing the tasks the thread has to perform
}
}
……………………………
}
……………………………
// create a thread and let it be in
created state
Thread thread2 = new Thread( new MyRunnable(…………)
);
Start/Run the Thread
Thread’s execution can be started simply by invoking the start() method
on the thread object created. It makes the new thread start it’s execution
path and the thread which invoked start() method will proceed it’s execution
to the next instructions in its path.
// thread1 starts running, then thread2
starts running, after that the current thread(one that executed the
statements “thread1.start();” and
// “thread2.start();” will proceed to execute the statements after them,
i.e "System.out.println" statement..
thread1.start();
thread2.start();
System.out.println(.........);
………………………….
Access the Current Thread
In Java current thread can be accessed by the static method of Thread class
currentThread() which returns the reference to the thread making the call
to the method. Apart from that the static methods on Thread class can be
directly be invoked so that they will work on the current thread. For
example Thread.sleep(30) will make the current thread to sleep for 30 milliseconds.
Sleep the Thread
When a thread has nothing to do for a particular interval of time, then
it can be slept by call to sleep() method on the thread. It takes millisecond
and nanosecond parameters so that thread can be slept to that precision.
After that time interval thread will wake up automatically to execute
the next instruction after the sleep method call.
……………………….
sleep(25); // invoked on the current thread object
……………………….
Thread.sleep(25); // invoked on thread executing this statement
………………………..
Wakeup the Thread from sleep
Threads will wake up automatically after sleeping for a particular period
of time. But their sleep can be disturbed by force which is shown
in the next few topics.
Suspend the Thread
Thread’s execution can be suspended indefinitely using suspend() method
, but it introduces potential problems like deadlocks. That’s why this method
is deprecated from many versions of Java. But the thread can still be suspended
using the object monitor related methods wait() and notify() of java.lang.Object.
Similarly thread’s suspension can be cancelled using the resume() method,
which is also deprecated for the same reasons. It also can be simulated using
the wait() and notify() methods.
Object which is the base class for all the java objects has 3 interesting
methods wait(), notify() and notifyAll(). Every object will have a monitor
that acts like a lock for the object. When a thread obtains the monitor
of the object, it can be thought that the thread has got the lock over the
object. wait() method when invoked on a particular object, it makes
the thread to wait till it gets the monitor of the object to proceed with
it’s execution. But when notify()/notifyAll() method is invoked it will
make one or all the threads which are waiting for monitor over the object
to wake up and obtain the monitor of the object. Only one will get the monitor
and rest of them will wait for the monitor again. All this depends on how
the wait() and notify methods are used. wait() method can be used with
or without time interval so that the waiting may be done for some time or
indefinitely. notify() method will wakeup only 1 selected thread based on
the policy of JVM implementation and notifyAll will wakeup all the
threads waiting for the monitor on the object.
To simulate the suspending and resuming of the threads we use the object
monitor related methods wait() and notify(). The basic algorithm for it
is
- Consider two threads, slave thread, the thread that is to be suspended
and resumed and the master thread which makes the slave thread to suspend
and resume.
- A boolean variable is used to indicate the slave thread if thread
should be in suspended state or not.
- In run method of the slave thread( or in any method called from run)
check from time to time the boolean variable’s value to decide if thread
has to be suspended state or not. If thread has to be suspended invoke wait()
method after ensuring that the thread has obtained lock over the object(using
synchronized statement). This makes the thread enter the wait state which
is equivalent to suspended state because thread is not executing any instructions.
public class MyThread extends Thread
{
………………………………
public boolean suspended = false;
……………………………….
public void run() {
try {
// basic initialization for thread run
int i=0;
// let this thread run infinitely till the thread is interrupted by master
thread
while(true) {
// when the thread is told to be suspended by master
thread ( by setting its value to true)
// if thread don’t have to be suspended then master thread
will set this to false so that wait() wont be called
while(suspended){
// obtain a lock over the current
thread object , synchronized(this) makes it thread safe
synchronized(this) {
//wait() forces the thread to wait, which is equivalent
to suspension of the thread
// when this thread has to be resumed then notify() will
be called by the master thread
wait();
}
}
//normal
work to be done by thread, i.e updating the progress bar
i = (i+1)%100;
progressBar.setValue(i);
//dalay
that makes the progress bar updated slowly so that it can be viewed comfortably
sleep(25);
}
}catch(InterruptedException iex){
} catch(Exception
ex) {
ex.printStackTrace();
}
} // end of run() method
}// end of MyThread class
4. When ever the thread has to be suspended,
then master thread will change the value of the boolean variable to
true. At beginning it’s value will be false. When it’s value turns
to true, the slave thread calls wait() method due to changed value.
//When suspend button is clicked change
the varaiable/flag to true that forces the slave thread to invoke wait()
void button_Suspend_actionPerformed(ActionEvent e)
{
((MyThread)thread1).suspended
= true;
…………………………………………..
}
5. When ever thread has to be resumed from
suspended state, master thread’s notify() method call will wake the thread
from its waiting state. This is similar to resuming the thread from suspension.
For invoking notify(), lock has to be obtained on the object. Also the boolean
variable has to be changed to false, because it should go back to suspended
state immediately after it is resumed.
//method handler for button press asking
to resume the thread
void button_Resume_actionPerformed(ActionEvent e) {
// set the flag to false
so that the thread wont go back to waiting state immediately after it is
awaken
((MyThread)thread1).suspended
= false;
// obtain a lock over
the thread object , synchronized(this) makes it thread safe
synchronized(thread1){
//make the thread
wake up from it’s waiting state, just like resuming
thread1.notify();
}
…………………………………
}
Resume the Thread
Thread’s indefinite suspension can be put to an end by resuming it using
the method resume(), but it introduces potential problems like deadlocks.
That’s why this method is deprecated from many versions of Java. But the
thread can still be suspended and resumed using the object monitor related
methods like wait() and notify(). Please refer to the section “Suspend the
Thread” to know how to do the simulation of suspending and resuming the thread.
Name the Thread
Thread’s name can be set by giving the name as the parameter to the thread’s
constructor. Apart from that threads name can be set using setName() method.
Also the thread’s name can be obtained using getName() method.
………………………
// Creates 2 threads with names T1and T2
Thread thread1 = new MyThread(threadGroup, progressBar1, "T1");
Thread thread2 = new Thread(threadGroup, new MyRunnable(progressBar2),
"T2");
…………………………
// rename T1 to Thread#1 and T2 to Thread#2
thread1.setName( "Thread#1");
thread2.setName( "Thread#2");
…………………………
// get the names of the threads
System.out.println("Created Thread:"+thread1.getName());
System.out.println("Created Thread:"+thread2.getName());
Set Priority to the Thread
Thread’s priority level can be set as normal, minimum or maximum. These
3 levels will be mapped to one of the many thread levels defined by the underlying
operating system. Java’s thread priority levels will be mapped drastically
differently on different operating systems based on the threading model
that the operating system defines. Thread priority can be defined using
setPriority() method and thread level defining constants Thread . MAX_PRIORITY,
Thread . NORM_PRIORITY and Thread . MIN_PRIORITY. Also the priority level
of a thread can be obtained using the method getPriority(). Effectiveness
of thread priorities is dependent on many factors like the implementation
of JDK, kind of tasks the threads are performing, mapping of thread priorities
to the operating system thread priorities, priority of the process,
etc.
…………………………………….
// set the priority to minimum
thread1.setPriority(Thread.MIN_PRIORITY);
…………………………
// get the threads priority
System.out.println("Created Thread:"+thread1.getName()+", with Priority:"+thread1.getPriority());
…………………………………….
Group the Threads
Threads can be bundled into a group so that the operations can be done
on all the threads collectively with single method calls. For example if
interrupt() method is called on a thread group, it is equivalent to invoking
the interrupt() method on each of the threads in that thread group.
…………………………….
// if thread1 and thread2 are in threadGroup, interrupt() can be called
on threadGroup instead of calling it on thread1 and
// thread2 individually
threadGroup.interrupt();
……………………………..
Threads can be added to a thread group by passing the thread group object’s
reference to the constructor of the thread object. Thread can access the
ThreadGroup to which it belongs using getThreadGroup() method. ThreadGroups
can contain both threads and threadgroups just as a filesystem directory
can hold both files and directories.
……………………………
// create a new threadgroup
ThreadGroup threadGroup = new ThreadGroup("MyThreadGroup");
System.out.println("Created ThreadGroup:"+threadGroup.getName()+", on the
Thread:"+Thread.currentThread().getName() );
// create thread so that it belongs to the thread group created above
Thread thread1 = new MyThread(threadGroup, progressBar1,"T1");
// Get the threadgroup(and it’s name) to which the thread belongs to
System.out.println("Created Thread:"+thread1.getName()+”, for ThreadGroup:"+thread1.getThreadGroup().getName());
Stop the Thread
Thread’s execution can be stopped in two ways. One way is when the run()
method is executed completely and the control returns from that method.
The other way is stopping the thread by force using the method like interrupt(),
stop() etc. stop() method is deprecated because it is source of some problems.
So interrupt() is considered to be the safe method to stop the execution
of the thread. To check if a thread is really interrupted or not, use interrupted(0
or isInterrupted() methods which returns boolean value to inform if a thread
is interrupted or not. In some versions of java the thread with maximum
priority cannot be interrupted.
……………………………………
// interrupt the thread
thread1.interrupt();
……………………………………
// interrupt all the threads in the thread group
threadGroup.interrupt();
……………………………………
// check if thread is interrupted, if it is not , then raise error
if(thread1.isInterrupted()==true) {
System.out.println("Stopped
the execution of Thread:"+thread1.getName());
}
else {
System.out.println("Failed
to stop the execution of Thread:"+thread1.getName());
JOptionPane.showMessageDialog(this,
"Failed to stop the execution of Thread:"+thread1.getName());
}
.......................................................
Destroy the Thread
Thread can be destroyed in a normal way and also by force. Destruction
of the thread can be done normally by stopping the thread and let it destruct.
It is the safer way to destruct the thread. But thread can be destructed
by force in special conditions like termination of a program etc where it
doesn’t matter what locks and monitors are being used. Use destroy() method
of the Thread class to destroy the thread by force, and the monitors
and locks will remain undisturbed, which is a side effect.
SourceCode Description
MainFrame.java
MainFrame class has the GUI and the event handling functionality. It is
derived from JFrame swing class and it has a panel to which the buttons
and the GUI controls are added. initThreads() method creates the threads from
MyRunnable and MyThread classes and associates those threads with the thread
group. Rest of the methods are for creating the GUI and event handling etc.
In the event handling methods the thread classes are manipulated as per the
requirement.
MyThread.java
MyThread class is a thread class derived from java.lang.Thread class. From
the constructor it gets the thread group to which it belongs to, name of
the thread and the progress bar with which it’s going to work. In run() method
it has the code for changing the progress of the progress bar from time
to time. Also it has the code for simulating suspend and resume states of
the thread. This class demonstrates creation of thread from a subclass of
java.lang.Thread and simulation of suspending and resuming the thread with
wait()/notify() method pair of java.lang.Object class.
MyRunnable.java
MyRunnable class is a thread class implementing java.lang.Runnable
interface. From the constructor it gets the progress bar with which it’s
going to work. The instance of this class will be associated with the instance
of java.lang.Thread instance, which will be associated to the thread group.
In run() method it has the code for changing the progress of the progress
from time to time. This class demonstrates creation of thread from the implementation
class of java.lang.Runnable interface and suspending and resuming the thread
with deprecated methods of java.lang.Thread class.