Unit - 4
Threads and Multithreading
Q1) Write short notes on multithreading?
A1) Multithreading
In Java, multithreading is the process of running several threads at the same time.
A thread is the smallest unit of processing and is a lightweight sub-process. Multitasking is accomplished through the use of multiprocessing and multithreading.
Because threads share memory, we employ multithreading rather than multiprocessing. They conserve memory by not allocating a separate memory space, and context-switching between threads takes less time than processing.
Multithreading in Java is typically utilized in gaming, animation, and other similar applications.
Because Java is a multi-threaded programming language, we can use it to create multi-threaded programs. A multi-threaded program is made up of two or more portions that can operate in parallel, each of which can tackle a distinct task at the same time, maximizing the use of available resources, especially when your computer has several CPUs.
Multitasking is defined as the sharing of common processing resources, such as a CPU, by many processes. Multi-threading extends the concept of multitasking into programs by allowing you to divide certain operations within a single app into several threads. Each thread can execute in its own thread. Not only does the operating system split processing time among distinct apps, but it also divides it among each thread within an application.
Multi-threading allows you to write software in which multiple activities can run at the same time.
Q2) Explain the Java Thread Model?
A2) Threads exist in several states. A thread can be running. It can be ready to run as soon as it gets CPU time. A running thread can be suspended, which temporarily halts its activity. A suspended thread can then be resumed, allowing it to pick up where it left off. A thread can be blocked when waiting for a resource. At any time, a thread can be terminated, which halts its execution immediately. Once terminated, a thread cannot be resumed.
Life Cycle of a Thread
A thread goes through various stages in its life cycle. For example, a thread is born, started, runs, and then dies. The following diagram shows the complete life cycle of a thread.
Fig - The complete life cycle of a thread
Following are the stages of the life cycle −
● New − A new thread begins its life cycle in the new state. It remains in this state until the program starts the thread. It is also referred to as a born thread.
● Runnable − After a newly born thread is started, the thread becomes runnable. A thread in this state is considered to be executing its task.
● Waiting − Sometimes, a thread transitions to the waiting state while the thread waits for another thread to perform a task. A thread transitions back to the runnable state only when another thread signals the waiting thread to continue executing.
● Timed Waiting − A runnable thread can enter the timed waiting state for a specified interval of time. A thread in this state transitions back to the runnable state when that time interval expires or when the event it is waiting for occurs.
● Terminated (Dead) − A runnable thread enters the terminated state when it completes its task or otherwise terminates.
Q3) Explain Thread Priorities in java?
A3) Java assigns to each thread a priority that determines how that thread should be treated with respect to the others. Thread priorities are integers that specify the relative priority of one thread to another. As an absolute value, a priority is meaningless; a higher-priority thread doesn’t run any faster than a lower-priority thread if it is the only thread running.
Instead, a thread’s priority is used to decide when to switch from one running thread to the next. This is called a context switch. The rules that determine when a context switch takes place are simple:
A thread can voluntarily relinquish control. This is done by explicitly yielding, sleeping, or blocking on pending I/O. In this scenario, all other threads are examined, and the highest-priority thread that is ready to run is given the CPU.
A thread can be preempted by a higher-priority thread. In this case, a lower-priority thread that does not yield the processor is simply preempted—no matter what it is doing— by a higher-priority thread. Basically, as soon as a higher-priority thread wants to run, it does. This is called preemptive multitasking.
In cases where two threads with the same priority are competing for CPU cycles, the situation is a bit complicated. For operating systems such as Windows, threads of equal priority are time-sliced automatically in round-robin fashion. For other types of operating systems, threads of equal priority must voluntarily yield control to their peers. If they don’t, the other threads will not run.
Q4) What is synchronization and messaging in java?
A4) Synchronization
Because multithreading introduces an asynchronous behavior to your programs, there must be a way for you to enforce synchronicity when you need it. For example, if you want two threads to communicate and share a complicated data structure, such as a linked list, you need some way to ensure that they don’t conflict with each other. That is, you must prevent one thread from writing data while another thread is in the middle of reading it.
For this purpose, Java implements an elegant twist on an age-old model of interprocess synchronization: the monitor. The monitor is a control mechanism first defined by C.A.R. Hoare. You can think of a monitor as a very small box that can hold only one thread. Once a thread enters a monitor, all other threads must wait until that thread exits the monitor. In this way, a monitor can be used to protect a shared asset from being manipulated by more than one thread at a time.
In Java, there is no class “Monitor”; instead, each object has its own implicit monitor that is automatically entered when one of the object’s synchronized methods is called. Once a thread is inside a synchronized method, no other thread can call any other synchronized method on the same object. This enables you to write very clear and concise multithreaded code, because synchronization support is built into the language.
Messaging
After you divide your program into separate threads, you need to define how they will communicate with each other. When programming with some other languages, you must depend on the operating system to establish communication between threads. This, of course, adds overhead. By contrast, Java provides a clean, low-cost way for two or more threads to talk to each other, via calls to predefined methods that all objects have. Java’s messaging system allows a thread to enter a synchronized method on an object, and then wait there until some other thread explicitly notifies it to come out.
Q5) What are thread methods?
A5) Following is the list of important methods available in the Thread class.
Sr.No. | Method & Description |
1 | Public void start() Starts the thread in a separate path of execution, then invokes the run() method on this Thread object. |
2 | Public void run() If this Thread object was instantiated using a separate Runnable target, the run() method is invoked on that Runnable object. |
3 | Public final void setName(String name) Changes the name of the Thread object. There is also a getName() method for retrieving the name. |
4 | Public final void setPriority(int priority) Sets the priority of this Thread object. The possible values are between 1 and 10. |
5 | Public final void setDaemon(boolean on) A parameter of true denotes this Thread as a daemon thread. |
6 | Public final void join(long millisec) The current thread invokes this method on a second thread, causing the current thread to block until the second thread terminates or the specified number of milliseconds passes. |
7 | Public void interrupt() Interrupts this thread, causing it to continue execution if it was blocked for any reason. |
8 | Public final boolean isAlive() Returns true if the thread is alive, which is any time after the thread has been started but before it runs to completion. |
The previous methods are invoked on a particular Thread object. The following methods in the Thread class are static. Invoking one of the static methods performs the operation on the currently running thread.
Sr.No. | Method & Description |
1 | Public static void yield() Causes the currently running thread to yield to any other threads of the same priority that are waiting to be scheduled. |
2 | Public static void sleep(long millisec) Causes the currently running thread to block for at least the specified number of milliseconds. |
3 | Public static boolean holdsLock(Object x) Returns true if the current thread holds the lock on the given Object. |
4 | Public static Thread currentThread() Returns a reference to the currently running thread, which is the thread that invokes this method. |
5 | Public static void dumpStack() Prints the stack trace for the currently running thread, which is useful when debugging a multithreaded application. |
Q6) Write any example of thread?
A6) The following Thread Class Demo program demonstrates some of these methods of the Thread class. Consider a class Display Message which implements Runnable −
// File Name : DisplayMessage.java
// Create a thread to implement Runnable
Public class DisplayMessage implements Runnable {
private String message;
public DisplayMessage(String message) {
this.message = message;
}
public void run() {
while(true) {
System.out.println(message);
}
}
}
Following is another class which extends the Thread class −
// File Name : GuessANumber.java
// Create a thread to extend Thread
Public class GuessANumber extends Thread {
private int number;
public GuessANumber(int number) {
this.number = number;
}
public void run() {
int counter = 0;
int guess = 0;
do {
guess = (int) (Math.random() * 100 + 1);
System.out.println(this.getName() + " guesses " + guess);
counter++;
} while(guess != number);
System.out.println("** Correct!" + this.getName() + "in" + counter + "guesses.**");
}
}
Following is the main program, which makes use of the above-defined classes −
// File Name : ThreadClassDemo.java
Public class ThreadClassDemo {
public static void main(String [] args) {
Runnable hello = new DisplayMessage("Hello");
Thread thread1 = new Thread(hello);
thread1.setDaemon(true);
thread1.setName("hello");
System.out.println("Starting hello thread...");
thread1.start();
Runnable bye = new DisplayMessage("Goodbye");
Thread thread2 = new Thread(bye);
thread2.setPriority(Thread.MIN_PRIORITY);
thread2.setDaemon(true);
System.out.println("Starting goodbye thread...");
thread2.start();
System.out.println("Starting thread3...");
Thread thread3 = new GuessANumber(27);
thread3.start();
try {
thread3.join();
} catch (InterruptedException e) {
System.out.println("Thread interrupted.");
}
System.out.println("Starting thread4...");
Thread thread4 = new GuessANumber(75);
thread4.start();
System.out.println("main() is ending...");
}
}
This will produce the following result. You can try this example again and again and you will get a different result every time.
Output
Starting hello thread...
Starting goodbye thread...
Hello
Hello
Hello
Hello
Hello
Hello
Goodbye
Goodbye
Goodbye
Goodbye
Goodbye
.......
Q7) What are the ways of creating thread?
A7)
A thread can be made in two ways:
- By extending Thread class
- By implementing Runnable interface.
By extending Thread class
Method for creating a thread is to use the two simple steps below to construct a new class that extends the Thread class. This technique allows you more flexibility when dealing with multiple threads established with the Thread class's various methods.
Step 1:
You'll need to override the Thread class's run( ) method. This method serves as the thread's entry point, and it's where you'll put all of your business logic. The run() method has the following simple syntax:
Public void run( )
Step 2:
You can start a Thread object by executing the start() method, which executes a call to the run() method. The start() method has the following simple syntax:
Void start( );
Example
Class ThreadDemo extends Thread {
private Thread t;
private String threadName;
ThreadDemo( String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// Let the thread sleep for a while.
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
Public class TestThread {
public static void main(String args[]) {
ThreadDemo T1 = new ThreadDemo( "Thread-1");
T1.start();
ThreadDemo T2 = new ThreadDemo( "Thread-2");
T2.start();
}
}
Output
Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.
By implementing Runnable interface
If you want your class to be run as a thread, you can do so by implementing the Runnable interface. You'll need to take three basic actions to get started.
Step 1:
You must first implement the run() method given by the Runnable interface. This method serves as the thread's entry point, and it's where you'll put all of your business logic. The run() method has the following simple syntax:
Public void run( )
Step 2:
In the next step, you'll create a Thread object with the constructor below.
Thread(Runnable threadObj, String threadName);
ThreadObj is an instance of a class that implements the Runnable interface, and threadName is the new thread's name.
Step 3:
You can start a Thread object by executing the start() method, which executes a call to the run( ) method. The start() method has the following simple syntax:
Void start();
Example
Class RunnableDemo implements Runnable {
private Thread t;
private String threadName;
RunnableDemo( String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// Let the thread sleep for a while.
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
Public class TestThread {
public static void main(String args[]) {
RunnableDemo R1 = new RunnableDemo( "Thread-1");
R1.start();
RunnableDemo R2 = new RunnableDemo( "Thread-2");
R2.start();
}
}
Output
Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.
Q8) How to create a thread by implementing a runnable interface?
A8) Create a Thread by Implementing a Runnable Interface
If your class is intended to be executed as a thread then you can achieve this by implementing a Runnable interface. You will need to follow three basic steps −
Step 1
As a first step, you need to implement a run() method provided by a Runnable interface. This method provides an entry point for the thread and you will put your complete business logic inside this method. Following is a simple syntax of the run() method −
Public void run( )
Step 2
As a second step, you will instantiate a Thread object using the following constructor −
Thread(Runnable threadObj, String threadName);
Where, threadObj is an instance of a class that implements the Runnable interface and threadName is the name given to the new thread.
Step 3
Once a Thread object is created, you can start it by calling start() method, which executes a call to run( ) method. Following is a simple syntax of start() method −
Void start();
Q9) What are the states in the lifecycle of a Thread?
A9) A thread can have one of the following states during its lifetime:
- New: In this state, a Thread class object is created using a new operator, but the thread is not alive. Thread doesn't start until we call the start() method.
- Runnable: In this state, the thread is ready to run after calling the start() method. However, the thread is not yet selected by the thread scheduler.
- Running: In this state, the thread scheduler picks the thread from the ready state, and the thread is running.
- Waiting/Blocked: In this state, a thread is not running but still alive, or it is waiting for the other thread to finish.
- Dead/Terminated: A thread is in terminated or dead state when the run() method exits.
Q10) How to create multiple threads?
A10)
Let’s see how to create multiple threads
Example
Class MyThread implements Runnable {
String name;
Thread t;
MyThread String thread){
name = threadname;
t = new Thread(this, name);
System.out.println("New thread: " + t);
t.start();
}
Public void run() {
Try {
for(int i = 5; i > 0; i--) {
System.out.println(name + ": " + i);
Thread.sleep(1000);
}
}catch (InterruptedException e) {
System.out.println(name + "Interrupted");
}
System.out.println(name + " exiting.");
}
}
Class MultiThread {
Public static void main(String args[]) {
new MyThread("One");
new MyThread("Two");
new NewThread("Three");
Try {
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}
System.out.println("Main thread exiting.");
}
}
Output
New thread: Thread[One,5,main]
New thread: Thread[Two,5,main]
New thread: Thread[Three,5,main]
One: 5
Two: 5
Three: 5
One: 4
Two: 4
Three: 4
One: 3
Three: 3
Two: 3
One: 2
Three: 2
Two: 2
One: 1
Three: 1
Two: 1
One exiting.
Two exiting.
Three exiting.
Q11) Write any example to create a new thread?
A11) Here is an example that creates a new thread and starts running it −
Class RunnableDemo implements Runnable {
private Thread t;
private String threadName;
RunnableDemo( String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// Let the thread sleep for a while.
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
Public class TestThread {
public static void main(String args[]) {
RunnableDemo R1 = new RunnableDemo( "Thread-1");
R1.start();
RunnableDemo R2 = new RunnableDemo( "Thread-2");
R2.start();
}
}
This will produce the following result −
Output
Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.
Q12) Describe synchronization?
A12) Synchronization in java is the capability to control the access of multiple threads to any shared resource.
Java Synchronization is a better option where we want to allow only one thread to access the shared resource.
When we start two or more threads in a program, it's possible that numerous threads will try to access the same resource, resulting in unexpected results due to concurrency difficulties. For example, if multiple threads try to write to the same file at the same time, the data may be corrupted because one of the threads can override data, or while one thread is opening and another is closing the same file.
As a result, it's necessary to synchronize many threads' actions and ensure that only one thread can access the resource at any given time. This is accomplished through the use of monitors. In Java, each object has its own monitor, which a thread can lock or unlock. On a display, only one thread can retain a lock at a time.
Using synchronized blocks, the Java programming language makes it relatively easy to create threads and synchronize their tasks. Within this block, you retain shared resources. The general form of the synchronized statement is as follows:
Syntax
Synchronized(objectidentifier)
{
// Access shared variables and other shared resources
}
The object identifier is a reference to an object whose lock corresponds to the monitor represented by the synchronized statement. Now we'll look at two different ways to print a counter using two distinct threads. When threads are not synchronized, they publish counter values that are out of order, but when we print counter inside a synchronized() block, it prints counters that are very much in order for both threads.
Multithreading Example with synchronization
Class PrintDemo {
public void printCount() {
try {
for(int i = 5; i > 0; i--) {
System.out.println("Counter --- " + i );
}
} catch (Exception e) {
System.out.println("Thread interrupted.");
}
}
}
Class ThreadDemo extends Thread {
private Thread t;
private String threadName;
PrintDemo PD;
ThreadDemo( String name, PrintDemo pd) {
threadName = name;
PD = pd;
}
public void run() {
synchronized(PD) {
PD.printCount();
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
Public class TestThread {
public static void main(String args[]) {
PrintDemo PD = new PrintDemo();
ThreadDemo T1 = new ThreadDemo( "Thread - 1 ", PD );
ThreadDemo T2 = new ThreadDemo( "Thread - 2 ", PD );
T1.start();
T2.start();
// wait for threads to end
try {
T1.join();
T2.join();
} catch ( Exception e) {
System.out.println("Interrupted");
}
}
}
Output
Starting Thread - 1
Starting Thread - 2
Counter --- 5
Counter --- 4
Counter --- 3
Counter --- 2
Counter --- 1
Thread Thread - 1 exiting.
Counter --- 5
Counter --- 4
Counter --- 3
Counter --- 2
Counter --- 1
Thread Thread - 2 exiting.
Q13) Write any program for synchronized method?
A13) If you declare any method as synchronized, it is known as synchronized method.
Synchronized method is used to lock an object for any shared resource.
When a thread invokes a synchronized method, it automatically acquires the lock for that object and releases it when the thread completes its task.
- //example of java synchronized method
- Class Table{
- Synchronized void printTable(int n){//synchronized method
- For(int i=1;i<=5;i++){
- System.out.println(n*i);
- Try{
- Thread.sleep(400);
- }catch(Exception e){System.out.println(e);}
- }
- }
- }
- Class MyThread1 extends Thread{
- Table t;
- MyThread1(Table t){
- This.t=t;
- }
- Public void run(){
- t.printTable(5);
- }
- }
- Class MyThread2 extends Thread{
- Table t;
- MyThread2(Table t){
- This.t=t;
- }
- Public void run(){
- t.printTable(100);
- }
- }
- Public class TestSynchronization2{
- Public static void main(String args[]){
- Table obj = new Table();//only one object
- MyThread1 t1=new MyThread1(obj);
- MyThread2 t2=new MyThread2(obj);
- t1.start();
- t2.start();
- }
- }
Output: 5
10
15
20
25
100
200
300
400
500
Q14) Write about isAlive() method.
A14)
Java Thread isAlive() method
The isAlive() method of thread class tests if the thread is alive. A thread is considered alive when the start() method of thread class has been called and the thread is not yet dead. This method returns true if the thread is still running and not finished.
Syntax
- Public final boolean isAlive()
Return
This method will return true if the thread is alive otherwise returns false.
Example
- Public class JavaIsAliveExp extends Thread
- {
- Public void run()
- {
- Try
- {
- Thread.sleep(300);
- System.out.println("is run() method isAlive "+Thread.currentThread().isAlive());
- }
- Catch (InterruptedException ie) {
- }
- }
- Public static void main(String[] args)
- {
- JavaIsAliveExp t1 = new JavaIsAliveExp();
- System.out.println("before starting thread isAlive: "+t1.isAlive());
- t1.start();
- System.out.println("after starting thread isAlive: "+t1.isAlive());
- }
- }
Output:
Before starting thread isAlive: false
After starting thread isAlive: true
Is run() method isAlive true
Q15) Explain join() method with example.
A15)
The join() method
The join() method waits for a thread to die. In other words, it causes the currently running threads to stop executing until the thread it joins with completes its task.
Syntax:
Public void join()throws InterruptedException
Public void join(long milliseconds)throws InterruptedException
Example of join() method
- Class TestJoinMethod1 extends Thread{
- Public void run(){
- For(int i=1;i<=5;i++){
- Try{
- Thread.sleep(500);
- }catch(Exception e){System.out.println(e);}
- System.out.println(i);
- }
- }
- Public static void main(String args[]){
- TestJoinMethod1 t1=new TestJoinMethod1();
- TestJoinMethod1 t2=new TestJoinMethod1();
- TestJoinMethod1 t3=new TestJoinMethod1();
- t1.start();
- Try{
- t1.join();
- }catch(Exception e){System.out.println(e);}
- t2.start();
- t3.start();
- }
- }
Output:
1
2
3
4
5
1
1
2
2
3
3
4
4
5
5
As you can see in the above example,when t1 completes its task then t2 and t3 starts executing.
Q16) Write about Inter-thread communication.
A16)
Inter-thread communication or Co-operation is all about allowing synchronized threads to communicate with each other.
Cooperation (Inter-thread communication) is a mechanism in which a thread is paused running in its critical section and another thread is allowed to enter (or lock) in the same critical section to be executed.
It is implemented by following methods of Object class:
- Wait()
- Notify()
- NotifyAll()
1) wait() method
The wait() method causes current thread to release the lock and wait until either another thread invokes the notify() method or the notifyAll() method for this object, or a specified amount of time has elapsed.
The current thread must own this object's monitor, so it must be called from the synchronized method only otherwise it will throw exception.
Method | Description |
Public final void wait()throws Interrupted Exception | It waits until object is notified. |
Public final void wait(long timeout)throws Interrupted Exception | It waits for the specified amount of time. |
2) notify() method
The notify() method wakes up a single thread that is waiting on this object's monitor.
If any threads are waiting on this object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation.
Syntax: public final void notify()
3) notifyAll() method
Wakes up all threads that are waiting on this object's monitor.
Syntax: public final void notifyAll()
Understanding the process of inter-thread communication
The point-to-point explanation of the above diagram is as follows:
- Threads enter to acquire lock.
- Lock is acquired by on thread.
- Now thread goes to waiting state if you call wait() method on the object. Otherwise, it releases the lock and exits.
- If you call notify() or notifyAll() method, thread moves to the notified state (runnable state).
- Now thread is available to acquire lock.
- After completion of the task, thread releases the lock and exits the monitor state of the object.
Q17) Write difference between wait and sleep.
A17)
Difference between wait and sleep
Wait() | Sleep() |
The wait() method releases the lock. | The sleep() method doesn't release the lock. |
It is a method of Object class | It is a method of Thread class |
It is the non-static method | It is the static method |
It should be notified by notify() or notifyAll() methods | After the specified amount of time, sleep is completed. |
Q18) Write multithreading example with synchronization .
A18)
Class PrintDemo {
public void printCount() {
try {
for(int i = 5; i > 0; i--) {
System.out.println("Counter --- " + i );
}
} catch (Exception e) {
System.out.println("Thread interrupted.");
}
}
}
Class ThreadDemo extends Thread {
private Thread t;
private String threadName;
PrintDemo PD;
ThreadDemo( String name, PrintDemo pd) {
threadName = name;
PD = pd;
}
public void run() {
synchronized(PD) {
PD.printCount();
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
Public class TestThread {
public static void main(String args[]) {
PrintDemo PD = new PrintDemo();
ThreadDemo T1 = new ThreadDemo( "Thread - 1 ", PD );
ThreadDemo T2 = new ThreadDemo( "Thread - 2 ", PD );
T1.start();
T2.start();
// wait for threads to end
try {
T1.join();
T2.join();
} catch ( Exception e) {
System.out.println("Interrupted");
}
}
}
Output
Starting Thread - 1
Starting Thread - 2
Counter --- 5
Counter --- 4
Counter --- 3
Counter --- 2
Counter --- 1
Thread Thread - 1 exiting.
Counter --- 5
Counter --- 4
Counter --- 3
Counter --- 2
Counter --- 1
Thread Thread - 2 exiting.