Multithreading in Java2_Life cycle of a Thread_27_11_2023(2)
Multithreading in Java2_Life cycle of a Thread_27_11_2023(2)
In Java, a thread always exists in any one of the following states. These states are:
1. New
2. Active
3. Blocked / Waiting
4. Timed Waiting
5. Terminated
Active: When a thread invokes the start() method, it moves from the new state to the
active state. The active state contains two states within it: one is runnable, and the other
is running.
o Runnable: A thread, that is ready to run is then moved to the runnable state. In
the runnable state, the thread may be running or may be ready to run at any given
instant of time. It is the duty of the thread scheduler to provide the thread time to
run, i.e., moving the thread the running state.
A program implementing multithreading acquires a fixed slice of time to each
individual thread. Each and every thread runs for a short span of time and when
that allocated time slice is over, the thread voluntarily gives up the CPU to the other
thread, so that the other threads can also run for their slice of time. Whenever such
a scenario occurs, all those threads that are willing to run, waiting for their turn to
run, lie in the runnable state. In the runnable state, there is a queue where the
threads lie.
o Running: When the thread gets the CPU, it moves from the runnable to the
running state. Generally, the most common change in the state of a thread is from
runnable to running and again back to runnable.
Blocked or Waiting: Whenever a thread is inactive for a span of time (not permanently)
then, either the thread is in the blocked state or is in the waiting state.
1
For example, a thread (let's say its name is A) may want to print some data from the
printer. However, at the same time, the other thread (let's say its name is B) is using the
printer to print some data. Therefore, thread A has to wait for thread B to use the printer.
Thus, thread A is in the blocked state. A thread in the blocked state is unable to perform
any execution and thus never consume any cycle of the Central Processing Unit (CPU).
Hence, we can say that thread A remains idle until the thread scheduler reactivates thread
A, which is in the waiting or blocked state.
When the main thread invokes the join() method then, it is said that the main thread is in
the waiting state. The main thread then waits for the child threads to complete their tasks.
When the child threads complete their job, a notification is sent to the main thread, which
again moves the thread from waiting to the active state.
If there are a lot of threads in the waiting or blocked state, then it is the duty of the thread
scheduler to determine which thread to choose and which one to reject, and the chosen
thread is then given the opportunity to run.
Timed Waiting: Sometimes, waiting for leads to starvation. For example, a thread (its
name is A) has entered the critical section of a code and is not willing to leave that critical
section. In such a scenario, another thread (its name is B) has to wait forever, which leads
to starvation. To avoid such scenario, a timed waiting state is given to thread B. Thus,
thread lies in the waiting state for a specific span of time, and not forever. A real example
of timed waiting is when we invoke the sleep() method on a specific thread. The sleep()
method puts the thread in the timed wait state. After the time runs out, the thread wakes
up and start its execution from when it has left earlier.
Terminated: A thread reaches the termination state because of the following reasons:
o When a thread has finished its job, then it exists or terminates normally.
o Abnormal termination: It occurs when some unusual events such as an
unhandled exception or segmentation fault.
A terminated thread means the thread is no more in the system. In other words, the thread
is dead, and there is no way one can respawn (active after kill) the dead thread.
The following diagram shows the different states involved in the life cycle of a thread.
2
Implementation of Thread States
In Java, one can get the current state of a thread using the Thread.getState() method.
The java.lang.Thread.State class of Java provides the constants ENUM to represent the
state of a thread. These constants are:
It represents the runnable state.It means a thread is waiting in the queue to run.
It represents the blocked state. In this state, the thread is waiting to acquire a lock.
It represents the waiting state. A thread will go to this state when it invokes the
Object.wait() method, or Thread.join() method with no timeout. A thread in the waiting
state is waiting for another thread to complete its task.
It represents the timed waiting state. The main difference between waiting and timed
waiting is the time constraint. Waiting has no time constraint, whereas timed waiting has
the time constraint. A thread invoking the following method reaches the timed waiting
state.
o sleep
o join with timeout
o wait with timeout
o parkUntil
o parkNanos
3
It represents the final state of a thread that is terminated or dead. A terminated thread
means it has completed its execution.
FileName: ThreadState.java
5
60. ABC myObj = new ABC();
61. Thread t2 = new Thread(myObj);
62.
63. // thread t2 is created and is currently in the NEW state.
64. System.out.println("The state of thread t2 after spawning it - "+ t2.getState());
65. t2.start();
66.
67. // thread t2 is moved to the runnable state
68. System.out.println("the state of thread t2 after calling the method start() on it - " + t2.ge
tState());
69.
70. // try-catch block for the smooth flow of the program
71. try
72. {
73. // moving the thread t1 to the state timed waiting
74. Thread.sleep(200);
75. }
76. catch (InterruptedException ie)
77. {
78. ie.printStackTrace();
79. }
80.
81. System.out.println("The state of thread t2 after invoking the method sleep() on it - "+ t2.
getState() );
82.
83. // try-catch block for the smooth flow of the program
84. try
85. {
86. // waiting for thread t2 to complete its execution
87. t2.join();
88. }
89. catch (InterruptedException ie)
90. {
91. ie.printStackTrace();
6
92. }
93. System.out.println("The state of thread t2 when it has completed it's execution - " + t2.g
etState());
94. }
95.
96. }
Output:
Explanation: Whenever we spawn a new thread, that thread attains the new state. When
the method start() is invoked on a thread, the thread scheduler moves that thread to the
runnable state. Whenever the join() method is invoked on any thread instance, the current
thread executing that statement has to wait for this thread to finish its execution, i.e.,
move that thread to the terminated state. Therefore, before the final print statement is
printed on the console, the program invokes the method join() on thread t2, making the
thread t1 wait while the thread t2 finishes its execution and thus, the thread t2 get to the
terminated or dead state. Thread t1 goes to the waiting state because it is waiting for
thread t2 to finish it's execution as it has invoked the method join() on thread t2.
7
Java Threads | How to create a thread in Java
There are two ways to create a thread:
Thread class:
Thread class provide constructors and methods to create and perform operations on a
thread.Thread class extends Object class and implements Runnable interface.
8
12. public Thread.State getState(): returns the state of the thread.
13. public boolean isAlive(): tests if the thread is alive.
14. public void yield(): causes the currently executing thread object to temporarily pause and
allow other threads to execute.
15. public void suspend(): is used to suspend the thread(depricated).
16. public void resume(): is used to resume the suspended thread(depricated).
17. public void stop(): is used to stop the thread(depricated).
18. public boolean isDaemon(): tests if the thread is a daemon thread.
19. public void setDaemon(boolean b): marks the thread as daemon or user thread.
20. public void interrupt(): interrupts the thread.
21. public boolean isInterrupted(): tests if the thread has been interrupted.
22. public static boolean interrupted(): tests if the current thread has been interrupted.
Runnable interface:
The Runnable interface should be implemented by any class whose instances are intended
to be executed by a thread. Runnable interface have only one method named run().
Starting a thread:
The start() method of Thread class is used to start a newly created thread. It performs
the following tasks:
9
1) Java Thread Example by extending Thread class
FileName: Multi.java
Output:
thread is running...
2) Java Thread Example by implementing Runnable interface
FileName: Multi3.java
Output:
thread is running...
10
If you are not extending the Thread class, your class object would not be treated as a
thread object. So you need to explicitly create the Thread class object. We are passing the
object of your class that implements Runnable so that your class run() method may
execute.
FileName: MyThread1.java
Output:
My first thread
11
FileName: MyThread2.java
Output:
My new thread
Now the thread is running ...
12
Thread Scheduler in Java
A component of Java that decides which thread to run or execute and which thread to
wait is called a thread scheduler in Java. In Java, a thread is only chosen by a thread
scheduler if it is in the runnable state. However, if there is more than one thread in the
runnable state, it is up to the thread scheduler to pick one of the threads and ignore the
other ones. There are some criteria that decide which thread will execute first. There are
two factors for scheduling a thread i.e. Priority and Time of arrival.
Priority: Priority of each thread lies between 1 to 10. If a thread has a higher priority, it
means that thread has got a better chance of getting picked up by the thread scheduler.
Time of Arrival: Suppose two threads of the same priority enter the runnable state, then
priority cannot be the factor to pick a thread from these two threads. In such a
case, arrival time of thread is considered by the thread scheduler. A thread that arrived
first gets the preference over the other threads.
t1 0
t2 1
t3 2
t4 3
13
In the above table, we can see that Thread t1 has arrived first, then Thread t2, then t3, and
at last t4, and the order in which the threads will be processed is according to the time of
arrival of threads.
Hence, Thread t1 will be processed first, and Thread t4 will be processed last.
Time-slicing scheduling:
Usually, the First Come First Serve algorithm is non-preemptive, which is bad as it may
lead to infinite blocking (also known as starvation). To avoid that, some time-slices are
provided to the threads so that after some time, the running thread has to give up the
CPU. Thus, the other waiting threads also get time to run their job.
14
In the above diagram, each thread is given a time slice of 2 seconds. Thus, after 2 seconds, the
first thread leaves the CPU, and the CPU is then captured by Thread2. The same process repeats
for the other threads too.
Preemptive-Priority Scheduling:
The name of the scheduling algorithm denotes that the algorithm is related to the priority
of the threads.
Suppose there are multiple threads available in the runnable state. The thread scheduler
picks that thread that has the highest priority. Since the algorithm is also preemptive,
therefore, time slices are also provided to the threads to avoid starvation. Thus, after some
time, even if the highest priority thread has not completed its job, it has to release the
CPU because of preemption.
15
Working of the Java Thread Scheduler
Let's understand the working of the Java thread scheduler. Suppose, there are five threads
that have different arrival times and different priorities. Now, it is the responsibility of the
thread scheduler to decide which thread will get the CPU first.
The thread scheduler selects the thread that has the highest priority, and the thread
begins the execution of the job. If a thread is already in runnable state and another thread
(that has higher priority) reaches in the runnable state, then the current thread is pre-
empted from the processor, and the arrived thread with higher priority gets the CPU time.
When two threads (Thread 2 and Thread 3) having the same priorities and arrival time,
the scheduling will be decided on the basis of FCFS algorithm. Thus, the thread that arrives
first gets the opportunity to execute first.
16
Thread.sleep() in Java with Examples
The Java Thread class provides the two variant of the sleep() method. First one accepts
only an arguments, whereas the other variant accepts two arguments. The method sleep()
is being used to halt the working of a thread for a given amount of time. The time up to
which the thread remains in the sleeping state is known as the sleeping time of the thread.
After the sleeping time is over, the thread starts its execution from where it has left.
The method sleep() with the one parameter is the native method, and the implementation
of the native method is accomplished in another programming language. The other
methods having the two parameters are not the native method. That is, its
implementation is accomplished in Java. We can access the sleep() methods with the help
of the Thread class, as the signature of the sleep() methods contain the static keyword.
The native, as well as the non-native method, throw a checked Exception. Therefore, either
try-catch block or the throws keyword can work here.
The Thread.sleep() method can be used with any thread. It means any other thread or the
main thread can invoke the sleep() method.
Parameters:
The following are the parameters used in the sleep() method.
mls: The time in milliseconds is represented by the parameter mls. The duration for which
the thread will sleep is given by the method sleep().
n: It shows the additional time up to which the programmer or developer wants the thread
to be in the sleeping state. The range of n is from 0 to 999999.
17
Important Points to Remember About the Sleep() Method
Whenever the Thread.sleep() methods execute, it always halts the execution of the current
thread.
Whenever another thread does interruption while the current thread is already in the sleep
mode, then the InterruptedException is thrown.
If the system that is executing the threads is busy, then the actual sleeping time of the
thread is generally more as compared to the time passed in arguments. However, if the
system executing the sleep() method has less load, then the actual sleeping time of the
thread is almost equal to the time passed in the argument.
FileName: TestSleepMethod1.java
Output:
18
1
1
2
2
3
3
4
4
As you know well that at a time only one thread is executed. If you sleep a thread for the
specified time, the thread scheduler picks up another thread and so on.
19
22. }
23. }
24. catch (Exception expn)
25. {
26. // catching the exception
27. System.out.println(expn);
28. }
29. }
30. }
Output:
0
1
2
3
4
FileName: TestSleepMethod3.java
20
13. {
14. for (int j = 0; j < 5; j++)
15. {
16.
17. // it throws the exception IllegalArgumentException
18. // as the time is -ive which is -100
19. Thread.sleep(-100);
20.
21. // displaying the variable's value
22. System.out.println(j);
23. }
24. }
25. catch (Exception expn)
26. {
27.
28. // the exception iscaught here
29. System.out.println(expn);
30. }
31. }
32. }
Output:
21
Can we start a thread twice
No. After starting a thread, it can never be started again. If you does so,
an IllegalThreadStateException is thrown. In such case, thread will run once but for second
time, it will throw exception.
Output:
running
Exception in thread "main" java.lang.IllegalThreadStateException
22
What if we call Java run() method directly instead
start() method?
o Each thread starts in a separate call stack.
o Invoking the run() method from the main thread, the run() method goes onto the
current call stack rather than at the beginning of a new call stack.
FileName: TestCallRun1.java
Output:
running...
FileName: TestCallRun2.java
23
10. TestCallRun2 t2=new TestCallRun2();
11.
12. t1.run();
13. t2.run();
14. }
15. }
Output:
1
2
3
4
1
2
3
4
As we can see in the above program that there is no context-switching because here t1
and t2 will be treated as normal object not thread object.
24
Syntax:
join(long mls): When the join() method is invoked, the current thread stops its execution
and the thread goes into the wait state. The current thread remains in the wait state until
the thread on which the join() method is invoked called is dead or the wait for the specified
time frame(in milliseconds) is over.
Syntax:
1. public final synchronized void join(long mls) throws InterruptedException, where mls is in mill
iseconds
join(long mls, int nanos): When the join() method is invoked, the current thread stops
its execution and go into the wait state. The current thread remains in the wait state until
the thread on which the join() method is invoked called is dead or the wait for the specified
time frame(in milliseconds + nanos) is over.
Syntax:
1. public final synchronized void join(long mls, int nanos) throws InterruptedException, where
mls is in milliseconds.
FileName: ThreadJoinExample.java
25
8. class ThreadJoin extends Thread
9. {
10. // overriding the run method
11. public void run()
12. {
13. for (int j = 0; j < 2; j++)
14. {
15. try
16. {
17. // sleeping the thread for 300 milli seconds
18. Thread.sleep(300);
19. System.out.println("The current thread name is: " + Thread.currentThread().getName());
20. }
21. // catch block for catching the raised exception
22. catch(Exception e)
23. {
24. System.out.println("The exception has been caught: " + e);
25. }
26. System.out.println( j );
27. }
28. }
29. }
30.
31. public class ThreadJoinExample
32. {
33. // main method
34. public static void main (String argvs[])
35. {
36.
37. // creating 3 threads
38. ThreadJoin th1 = new ThreadJoin();
39. ThreadJoin th2 = new ThreadJoin();
40. ThreadJoin th3 = new ThreadJoin();
41.
26
42. // thread th1 starts
43. th1.start();
44.
45. // starting the second thread after when
46. // the first thread th1 has ended or died.
47. try
48. {
49. System.out.println("The current thread name is: "+ Thread.currentThread().getName());
50.
51. // invoking the join() method
52. th1.join();
53. }
54.
55. // catch block for catching the raised exception
56. catch(Exception e)
57. {
58. System.out.println("The exception has been caught " + e);
59. }
60.
61. // thread th2 starts
62. th2.start();
63.
64. // starting the th3 thread after when the thread th2 has ended or died.
65. try
66. {
67. System.out.println("The current thread name is: " + Thread.currentThread().getName());
68. th2.join();
69. }
70.
71. // catch block for catching the raised exception
72. catch(Exception e)
73. {
74. System.out.println("The exception has been caught " + e);
75. }
27
76.
77. // thread th3 starts
78. th3.start();
79. }
80. }
Output:
Explanation: The above program shows that the second thread th2 begins after the first
thread th1 has ended, and the thread th3 starts its work after the second thread th2 has
ended or died.
FileName: ThreadJoinExample1.java
28
8. threadToInterrupt.interrupt();
9. }
10. }
11.
12.
13. public class ThreadJoinExample1
14. {
15. // main method
16. public static void main(String[] argvs)
17. {
18. try
19. {
20. // creating an object of the class ABC
21. ABC th1 = new ABC();
22.
23. th1.threadToInterrupt = Thread.currentThread();
24. th1.start();
25.
26. // invoking the join() method leads
27. // to the generation of InterruptedException
28. th1.join();
29. }
30. catch (InterruptedException ex)
31. {
32. System.out.println("The exception has been caught. " + ex);
33. }
34. }
35. }
Output:
29
Filename: TestJoinMethod1.java
Output:
1
2
3
4
5
1
1
2
2
3
3
30
4
4
5
5
We can see in the above example, when t1 completes its task then t2 and t3 starts
executing.
Output:
1
2
31
3
1
4
1
2
5
2
3
3
4
4
5
5
In the above example, when t1 completes its task for 1500 milliseconds(3 times), then t2
and t3 start executing.
We can also set the name of a thread directly when we create a new thread using the
constructor of the class.
32
7. TestMultiNaming1 t2=new TestMultiNaming1();
8. System.out.println("Name of t1:"+t1.getName());
9. System.out.println("Name of t2:"+t2.getName());
10.
11. t1.start();
12. t2.start();
13.
14. t1.setName("Sonoo Jaiswal");
15. System.out.println("After changing name of t1:"+t1.getName());
16. }
17. }
Output:
Name of t1:Thread-0
Name of t2:Thread-1
After changing name of t1:Sonoo Jaiswal
running...
running...
Example of naming a thread : Without Using setName()
Method
One can also set the name of a thread at the time of the creation of a thread, without
using the setName() method. Observe the following code.
FileName: ThreadNamingExample.java
33
12. // constructor of the class
13. ThreadName(String threadName)
14. {
15. // invoking the constructor of
16. // the superclass, which is Thread class.
17. super(threadName);
18. }
19.
20. // overriding the method run()
21. public void run()
22. {
23. System.out.println(" The thread is executing....");
24. }
25. }
26.
27. public class ThreadNamingExample
28. {
29. // main method
30. public static void main (String argvs[])
31. {
32. // creating two threads and settting their name
33. // using the contructor of the class
34. ThreadName th1 = new ThreadName("JavaTpoint1");
35. ThreadName th2 = new ThreadName("JavaTpoint2");
36.
37. // invoking the getName() method to get the names
38. // of the thread created above
39. System.out.println("Thread - 1: " + th1.getName());
40. System.out.println("Thread - 2: " + th2.getName());
41.
42.
43. // invoking the start() method on both the threads
44. th1.start();
45. th2.start();
34
46. }
47. }
Output:
Thread - 1: JavaTpoint1
Thread - 2: JavaTpoint2
The thread is executing....
The thread is executing....
Current Thread
The currentThread() method returns a reference of the currently executing thread.
Output:
Thread-0
Thread-1
36
8. // Whenever the start() method is called by a thread
9. // the run() method is invoked
10. public void run()
11. {
12. // the print statement
13. System.out.println("Inside the run() method");
14. }
15.
16. // the main method
17. public static void main(String argvs[])
18. {
19. // Creating threads with the help of ThreadPriorityExample class
20. ThreadPriorityExample th1 = new ThreadPriorityExample();
21. ThreadPriorityExample th2 = new ThreadPriorityExample();
22. ThreadPriorityExample th3 = new ThreadPriorityExample();
23.
24. // We did not mention the priority of the thread.
25. // Therefore, the priorities of the thread is 5, the default value
26.
27. // 1st Thread
28. // Displaying the priority of the thread
29. // using the getPriority() method
30. System.out.println("Priority of the thread th1 is : " + th1.getPriority());
31.
32. // 2nd Thread
33. // Display the priority of the thread
34. System.out.println("Priority of the thread th2 is : " + th2.getPriority());
35.
36. // 3rd Thread
37. // // Display the priority of the thread
38. System.out.println("Priority of the thread th2 is : " + th2.getPriority());
39.
40. // Setting priorities of above threads by
41. // passing integer arguments
37
42. th1.setPriority(6);
43. th2.setPriority(3);
44. th3.setPriority(9);
45.
46. // 6
47. System.out.println("Priority of the thread th1 is : " + th1.getPriority());
48.
49. // 3
50. System.out.println("Priority of the thread th2 is : " + th2.getPriority());
51.
52. // 9
53. System.out.println("Priority of the thread th3 is : " + th3.getPriority());
54.
55. // Main thread
56.
57. // Displaying name of the currently executing thread
58. System.out.println("Currently Executing The Thread : " + Thread.currentThread().getName());
59.
60. System.out.println("Priority of the main thread is : " + Thread.currentThread().getPriority());
61.
62. // Priority of the main thread is 10 now
63. Thread.currentThread().setPriority(10);
64.
65. System.out.println("Priority of the main thread is : " + Thread.currentThread().getPriority());
66. }
67. }
Output:
38
We know that a thread with high priority will get preference over lower priority threads
when it comes to the execution of threads. However, there can be other scenarios where
two threads can have the same priority. All of the processing, in order to look after the
threads, is done by the Java thread scheduler. Refer to the following example to
comprehend what will happen if two threads have the same priority.
FileName: ThreadPriorityExample1.java
39
28. // using the getPriority() method of the Thread class
29. System.out.println("Priority of the main thread is : " + Thread.currentThread().getPriority());
30.
31. // creating a thread by creating an object of the class ThreadPriorityExample1
32. ThreadPriorityExample1 th1 = new ThreadPriorityExample1();
33.
34. // th1 thread is the child of the main thread
35. // therefore, the th1 thread also gets the priority 7
36.
37. // Displaying the priority of the current thread
38. System.out.println("Priority of the thread th1 is : " + th1.getPriority());
39. }
40. }
Output:
Explanation: If there are two threads that have the same priority, then one can not predict
which thread will get the chance to execute first. The execution then is dependent on the
thread scheduler's algorithm (First Come First Serve, Round-Robin, etc.)
Example of IllegalArgumentException
We know that if the value of the parameter newPriority of the method getPriority() goes
out of the range (1 to 10), then we get the IllegalArgumentException. Let's observe the
same with the help of an example.
FileName: IllegalArgumentException.java
40
8. public static void main(String argvs[])
9. {
10.
11. // Now, priority of the main thread is set to 17, which is greater than 10
12. Thread.currentThread().setPriority(17);
13.
14. // The current thread is retrieved
15. // using the currentThread() method
16.
17. // displaying the main thread priority
18. // using the getPriority() method of the Thread class
19. System.out.println("Priority of the main thread is : " + Thread.currentThread().getPriority());
20.
21. }
22. }
There are many java daemon threads running automatically e.g. gc, finalizer etc.
You can see all the detail by typing the jconsole in the command prompt. The jconsole
tool provides information about the loaded classes, memory usage, running threads etc.
41
o Its life depends on user threads.
o It is a low priority thread.
1) public void setDaemon(boolean is used to mark the current thread as daemon thread or user
status) thread.
42
12. TestDaemonThread1 t2=new TestDaemonThread1();
13. TestDaemonThread1 t3=new TestDaemonThread1();
14.
15. t1.setDaemon(true);//now t1 is daemon thread
16.
17. t1.start();//starting threads
18. t2.start();
19. t3.start();
20. }
21. }
Output:
File: MyThread.java
Output:
43
exception in thread main: java.lang.IllegalThreadStateException
In the case of a thread pool, a group of fixed-size threads is created. A thread from the
thread pool is pulled out and assigned a job by the service provider. After completion of
the job, the thread is contained in the thread pool again.
newCachedThreadPool(): The method creates a new thread pool that creates the new
threads when needed but will still use the previously created thread whenever they are
available to use.
File: WorkerThread.java
1. import java.util.concurrent.ExecutorService;
44
2. import java.util.concurrent.Executors;
3. class WorkerThread implements Runnable {
4. private String message;
5. public WorkerThread(String s){
6. this.message=s;
7. }
8. public void run() {
9. System.out.println(Thread.currentThread().getName()+" (Start) message = "+message);
10. processmessage();//call processmessage method that sleeps the thread for 2 seconds
11. System.out.println(Thread.currentThread().getName()+" (End)");//prints thread name
12. }
13. private void processmessage() {
14. try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); }
15. }
16. }
File: TestThreadPool.java
Output:
45
pool-1-thread-3 (Start) message = 2
pool-1-thread-5 (Start) message = 4
pool-1-thread-4 (Start) message = 3
pool-1-thread-2 (End)
pool-1-thread-2 (Start) message = 5
pool-1-thread-1 (End)
pool-1-thread-1 (Start) message = 6
pool-1-thread-3 (End)
pool-1-thread-3 (Start) message = 7
pool-1-thread-4 (End)
pool-1-thread-4 (Start) message = 8
pool-1-thread-5 (End)
pool-1-thread-5 (Start) message = 9
pool-1-thread-2 (End)
pool-1-thread-1 (End)
pool-1-thread-4 (End)
pool-1-thread-3 (End)
pool-1-thread-5 (End)
Finished all threads
FileName: ThreadPoolExample.java
46
14. {
15. // initializing the field taskName
16. taskName = str;
17. }
18.
19. // Printing the task name and then sleeps for 1 sec
20. // The complete process is getting repeated five times
21. public void run()
22. {
23. try
24. {
25. for (int j = 0; j <= 5; j++)
26. {
27. if (j == 0)
28. {
29. Date dt = new Date();
30. SimpleDateFormat sdf = new SimpleDateFormat("hh : mm : ss");
31.
32. //prints the initialization time for every task
33. System.out.println("Initialization time for the task name: "+ taskName + " = " + sdf.format(dt));
34.
35. }
36. else
37. {
38. Date dt = new Date();
39. SimpleDateFormat sdf = new SimpleDateFormat("hh : mm : ss");
40.
41. // prints the execution time for every task
42. System.out.println("Time of execution for the task name: " + taskName + " = " +sdf.format(dt));
43.
44. }
45.
46. // 1000ms = 1 sec
47. Thread.sleep(1000);
47
48. }
49.
50. System.out.println(taskName + " is complete.");
51. }
52.
53. catch(InterruptedException ie)
54. {
55. ie.printStackTrace();
56. }
57. }
58. }
59.
60. public class ThreadPoolExample
61. {
62. // Maximum number of threads in the thread pool
63. static final int MAX_TH = 3;
64.
65. // main method
66. public static void main(String argvs[])
67. {
68. // Creating five new tasks
69. Runnable rb1 = new Tasks("task 1");
70. Runnable rb2 = new Tasks("task 2");
71. Runnable rb3 = new Tasks("task 3");
72. Runnable rb4 = new Tasks("task 4");
73. Runnable rb5 = new Tasks("task 5");
74.
75. // creating a thread pool with MAX_TH number of
76. // threads size the pool size is fixed
77. ExecutorService pl = Executors.newFixedThreadPool(MAX_TH);
78.
79. // passes the Task objects to the pool to execute (Step 3)
80. pl.execute(rb1);
81. pl.execute(rb2);
48
82. pl.execute(rb3);
83. pl.execute(rb4);
84. pl.execute(rb5);
85.
86. // pool is shutdown
87. pl.shutdown();
88. }
89. }
Output:
49
Time of execution for the task name: task 5 = 06 : 13 : 13
Time of execution for the task name: task 4 = 06 : 13 : 14
Time of execution for the task name: task 5 = 06 : 13 : 14
task 4 is complete.
task 5 is complete.
Explanation: It is evident by looking at the output of the program that tasks 4 and 5 are
executed only when the thread has an idle thread. Until then, the extra tasks are put in
the queue.
The takeaway from the above example is when one wants to execute 50 tasks but is not
willing to create 50 threads. In such a case, one can create a pool of 10 threads. Thus, 10
out of 50 tasks are assigned, and the rest are put in the queue. Whenever any thread out
of 10 threads becomes idle, it picks up the 11th task. The other pending tasks are treated
the same way.
Deadlock: It is a known fact that deadlock can come in any program that involves
multithreading, and a thread pool introduces another scenario of deadlock. Consider a
scenario where all the threads that are executing are waiting for the results from the
threads that are blocked and waiting in the queue because of the non-availability of
threads for the execution.
Thread Leakage: Leakage of threads occurs when a thread is being removed from the
pool to execute a task but is not returning to it after the completion of the task. For
example, when a thread throws the exception and the pool class is not able to catch this
exception, then the thread exits and reduces the thread pool size by 1. If the same thing
repeats a number of times, then there are fair chances that the pool will become empty,
and hence, there are no threads available in the pool for executing other requests.
Resource Thrashing: A lot of time is wasted in context switching among threads when
the size of the thread pool is very large. Whenever there are more threads than the
optimal number may cause the starvation problem, and it leads to resource thrashing.
Points to Remember
Do not queue the tasks that are concurrently waiting for the results obtained from the
other tasks. It may lead to a deadlock situation, as explained above.
50
Care must be taken whenever threads are used for the operation that is long-lived. It may
result in the waiting of thread forever and will finally lead to the leakage of the resource.
In the end, the thread pool has to be ended explicitly. If it does not happen, then the
program continues to execute, and it never ends. Invoke the shutdown() method on the
thread pool to terminate the executor. Note that if someone tries to send another task to
the executor after shutdown, it will throw a RejectedExecutionException.
One needs to understand the tasks to effectively tune the thread pool. If the given tasks
are contrasting, then one should look for pools for executing different varieties of tasks
so that one can properly tune them.
To reduce the probability of running JVM out of memory, one can control the maximum
threads that can run in JVM. The thread pool cannot create new threads after it has
reached the maximum limit.
A thread pool can use the same used thread if the thread has finished its execution. Thus,
the time and resources used for the creation of a new thread are saved.
Conclusion
A thread pool is a very handy tool for organizing applications, especially on the server-
side. Concept-wise, a thread pool is very easy to comprehend. However, one may have to
look at a lot of issues when dealing with a thread pool. It is because the thread pool comes
with some risks involved it (risks are discussed above).
ThreadGroup in Java
Java provides a convenient way to group multiple threads in a single object. In such a way,
we can suspend, resume or interrupt a group of threads by a single method call.
51
Note: Now suspend(), resume() and stop() methods are deprecated.
A ThreadGroup represents a set of threads. A thread group can also include the other
thread group. The thread group creates a tree in which every thread group except the
initial thread group has a parent.
A thread is allowed to access information about its own thread group, but it cannot access
the information about its thread group's parent thread group or any other thread groups.
2) ThreadGroup(ThreadGroup parent, String creates a thread group with a given parent group and
name) name.
52
S.N. Modifier and Method Description
Type
4) void destroy() This method destroys the thread group and all of its
subgroups.
5) int enumerate(Thread[] list) This method copies into the specified array every active
thread in the thread group and its subgroups.
6) int getMaxPriority() This method returns the maximum priority of the thread
group.
7) String getName() This method returns the name of the thread group.
8) ThreadGroup getParent() This method returns the parent of the thread group.
9) void interrupt() This method interrupts all threads in the thread group.
10) boolean isDaemon() This method tests if the thread group is a daemon thread
group.
11) void setDaemon(boolean This method changes the daemon status of the thread
daemon) group.
12) boolean isDestroyed() This method tests if this thread group has been
destroyed.
13) void list() This method prints information about the thread group
to the standard output.
53
14) boolean parentOf(ThreadGroup g This method tests if the thread group is either the thread
group argument or one of its ancestor thread groups.
15) void suspend() This method is used to suspend all threads in the thread
group.
16) void resume() This method is used to resume all threads in the thread
group which was suspended using suspend() method.
17) void setMaxPriority(int pri) This method sets the maximum priority of the group.
18) void stop() This method is used to stop all threads in the thread
group.
Now all 3 threads belong to one group. Here, tg1 is the thread group name, MyRunnable
is the class that implements Runnable interface and "one", "two" and "three" are the
thread names.
1. Thread.currentThread().getThreadGroup().interrupt();
ThreadGroup Example
File: ThreadGroupDemo.java
54
8.
9. Thread t1 = new Thread(tg1, runnable,"one");
10. t1.start();
11. Thread t2 = new Thread(tg1, runnable,"two");
12. t2.start();
13. Thread t3 = new Thread(tg1, runnable,"three");
14. t3.start();
15.
16. System.out.println("Thread Group Name: "+tg1.getName());
17. tg1.list();
18.
19. }
20. }
Output:
one
two
three
Thread Group Name: Parent ThreadGroup
java.lang.ThreadGroup[name=Parent ThreadGroup,maxpri=10]
FileName: ActiveCountExample.java
55
10. ThreadNew(String tName, ThreadGroup tgrp)
11. {
12. super(tgrp, tName);
13. start();
14. }
15.
16. // overriding the run method
17. public void run()
18. {
19.
20. for (int j = 0; j < 1000; j++)
21. {
22. try
23. {
24. Thread.sleep(5);
25. }
26. catch (InterruptedException e)
27. {
28. System.out.println("The exception has been encountered " + e);
29. }
30. }
31. }
32. }
33.
34. public class ActiveCountExample
35. {
36. // main method
37. public static void main(String argvs[])
38. {
39. // creating the thread group
40. ThreadGroup tg = new ThreadGroup("The parent group of threads");
41.
42. ThreadNew th1 = new ThreadNew("first", tg);
43. System.out.println("Starting the first");
56
44.
45. ThreadNew th2 = new ThreadNew("second", tg);
46. System.out.println("Starting the second");
47.
48. // checking the number of active thread by invoking the activeCount() method
49. System.out.println("The total number of active threads are: " + tg.activeCount());
50. }
51. }
Output:
FileName: ActiveGroupCountExample.java
57
17. public void run()
18. {
19.
20. for (int j = 0; j < 100; j++)
21. {
22. try
23. {
24. Thread.sleep(5);
25. }
26. catch (InterruptedException e)
27. {
28. System.out.println("The exception has been encountered " + e);
29. }
30.
31. }
32.
33. System.out.println(Thread.currentThread().getName() + " thread has finished executing");
34. }
35. }
36.
37. public class ActiveGroupCountExample
38. {
39. // main method
40. public static void main(String argvs[])
41. {
42. // creating the thread group
43. ThreadGroup tg = new ThreadGroup("The parent group of threads");
44.
45. ThreadGroup tg1 = new ThreadGroup(tg, "the child group");
46.
47. ThreadNew th1 = new ThreadNew("the first", tg);
48. System.out.println("Starting the first");
49.
50. ThreadNew th2 = new ThreadNew("the second", tg);
58
51. System.out.println("Starting the second");
52.
53. // checking the number of active thread by invoking the activeGroupCount() method
54. System.out.println("The total number of active thread groups are: " + tg.activeGroupCount());
55. }
56. }
Output:
FileName: DestroyExample.java
59
18. {
19.
20. for (int j = 0; j < 100; j++)
21. {
22. try
23. {
24. Thread.sleep(5);
25. }
26. catch (InterruptedException e)
27. {
28. System.out.println("The exception has been encountered " + e);
29. }
30.
31. }
32.
33. System.out.println(Thread.currentThread().getName() + " thread has finished executing");
34. }
35. }
36.
37. public class DestroyExample
38. {
39. // main method
40. public static void main(String argvs[]) throws SecurityException, InterruptedException
41. {
42. // creating the thread group
43. ThreadGroup tg = new ThreadGroup("the parent group");
44.
45. ThreadGroup tg1 = new ThreadGroup(tg, "the child group");
46.
47. ThreadNew th1 = new ThreadNew("the first", tg);
48. System.out.println("Starting the first");
49.
50. ThreadNew th2 = new ThreadNew("the second", tg);
51. System.out.println("Starting the second");
60
52.
53. // waiting until the other threads has been finished
54. th1.join();
55. th2.join();
56.
57. // destroying the child thread group
58. tg1.destroy();
59. System.out.println(tg1.getName() + " is destroyed.");
60.
61. // destroying the parent thread group
62. tg.destroy();
63. System.out.println(tg.getName() + " is destroyed.");
64. }
65. }
Output:
FileName: EnumerateExample.java
61
8. {
9. // constructor of the class
10. ThreadNew(String tName, ThreadGroup tgrp)
11. {
12. super(tgrp, tName);
13. start();
14. }
15.
16. // overriding the run() method
17. public void run()
18. {
19.
20. for (int j = 0; j < 100; j++)
21. {
22. try
23. {
24. Thread.sleep(5);
25. }
26. catch (InterruptedException e)
27. {
28. System.out.println("The exception has been encountered " + e);
29. }
30.
31. }
32.
33. System.out.println(Thread.currentThread().getName() + " thread has finished executing");
34. }
35. }
36.
37. public class EnumerateExample
38. {
39. // main method
40. public static void main(String argvs[]) throws SecurityException, InterruptedException
41. {
62
42. // creating the thread group
43. ThreadGroup tg = new ThreadGroup("the parent group");
44.
45. ThreadGroup tg1 = new ThreadGroup(tg, "the child group");
46.
47. ThreadNew th1 = new ThreadNew("the first", tg);
48. System.out.println("Starting the first");
49.
50. ThreadNew th2 = new ThreadNew("the second", tg);
51. System.out.println("Starting the second");
52.
53. // returning the number of threads kept in this array
54. Thread[] grp = new Thread[tg.activeCount()];
55. int cnt = tg.enumerate(grp);
56. for (int j = 0; j < cnt; j++)
57. {
58. System.out.println("Thread " + grp[j].getName() + " is found.");
59. }
60. }
61. }
Output:
FileName: GetMaxPriorityExample.java
63
2.
3. // import statement
4. import java.lang.*;
5.
6.
7. class ThreadNew extends Thread
8. {
9. // constructor of the class
10. ThreadNew(String tName, ThreadGroup tgrp)
11. {
12. super(tgrp, tName);
13. start();
14. }
15.
16. // overriding the run() method
17. public void run()
18. {
19.
20. for (int j = 0; j < 100; j++)
21. {
22. try
23. {
24. Thread.sleep(5);
25. }
26. catch (InterruptedException e)
27. {
28. System.out.println("The exception has been encountered " + e);
29. }
30.
31. }
32.
33. System.out.println(Thread.currentThread().getName() + " thread has finished executing");
34. }
35. }
64
36.
37. public class GetMaxPriorityExample
38. {
39. // main method
40. public static void main(String argvs[]) throws SecurityException, InterruptedException
41. {
42. // creating the thread group
43. ThreadGroup tg = new ThreadGroup("the parent group");
44.
45. ThreadGroup tg1 = new ThreadGroup(tg, "the child group");
46.
47. ThreadNew th1 = new ThreadNew("the first", tg);
48. System.out.println("Starting the first");
49.
50. ThreadNew th2 = new ThreadNew("the second", tg);
51. System.out.println("Starting the second");
52.
53. int priority = tg.getMaxPriority();
54.
55. System.out.println("The maximum priority of the parent ThreadGroup: " + priority);
56.
57.
58. }
59. }
Output:
65
Now, we will learn how one can use the getParent() method in the code.
FileName: GetParentExample.java
66
32.
33. System.out.println(Thread.currentThread().getName() + " thread has finished executing");
34. }
35. }
36.
37. public class GetMaxPriorityExample
38. {
39. // main method
40. public static void main(String argvs[]) throws SecurityException, InterruptedException
41. {
42. // creating the thread group
43. ThreadGroup tg = new ThreadGroup("the parent group");
44.
45. ThreadGroup tg1 = new ThreadGroup(tg, "the child group");
46.
47. ThreadNew th1 = new ThreadNew("the first", tg);
48. System.out.println("Starting the first");
49.
50. ThreadNew th2 = new ThreadNew("the second", tg);
51. System.out.println("Starting the second");
52.
53. // printing the parent ThreadGroup
54. // of both child and parent threads
55. System.out.println("The ParentThreadGroup for " + tg.getName() + " is " + tg.getParent().getNa
me());
56. System.out.println("The ParentThreadGroup for " + tg1.getName() + " is " + tg1.getParent().getN
ame());
57.
58.
59. }
60. }
Output:
67
Starting the second
The ParentThreadGroup for the parent group is main
The ParentThreadGroup for the child group is the parent group
the first thread has finished executing
the second thread has finished executing
FileName: InterruptExample.java
68
25. }
26. catch (InterruptedException e)
27. {
28. System.out.println("The exception has been encountered " + e);
29. }
30.
31. }
32.
33. System.out.println(Thread.currentThread().getName() + " thread has finished executing");
34. }
35. }
36.
37. public class InterruptExample
38. {
39. // main method
40. public static void main(String argvs[]) throws SecurityException, InterruptedException
41. {
42. // creating the thread group
43. ThreadGroup tg = new ThreadGroup("the parent group");
44.
45. ThreadGroup tg1 = new ThreadGroup(tg, "the child group");
46.
47. ThreadNew th1 = new ThreadNew("the first", tg);
48. System.out.println("Starting the first");
49.
50. ThreadNew th2 = new ThreadNew("the second", tg);
51. System.out.println("Starting the second");
52.
53. // invoking the interrupt method
54. tg.interrupt();
55.
56. }
57. }
69
Output:
FileName: IsDaemonExample.java
70
22. try
23. {
24. Thread.sleep(5);
25. }
26. catch (InterruptedException e)
27. {
28. System.out.println("The exception has been encountered" + e);
29. }
30.
31. }
32.
33. System.out.println(Thread.currentThread().getName() + " thread has finished executing");
34. }
35. }
36.
37. public class IsDaemonExample
38. {
39. // main method
40. public static void main(String argvs[]) throws SecurityException, InterruptedException
41. {
42. // creating the thread group
43. ThreadGroup tg = new ThreadGroup("the parent group");
44.
45. ThreadGroup tg1 = new ThreadGroup(tg, "the child group");
46.
47. ThreadNew th1 = new ThreadNew("the first", tg);
48. System.out.println("Starting the first");
49.
50. ThreadNew th2 = new ThreadNew("the second", tg);
51. System.out.println("Starting the second");
52.
53. if (tg.isDaemon() == true)
54. {
55. System.out.println("The group is a daemon group.");
71
56. }
57. else
58. {
59. System.out.println("The group is not a daemon group.");
60. }
61.
62. }
63. }
Output:
FileName: IsDestroyedExample.java
72
15.
16. // overriding the run() method
17. public void run()
18. {
19.
20. for (int j = 0; j < 100; j++)
21. {
22. try
23. {
24. Thread.sleep(5);
25. }
26. catch (InterruptedException e)
27. {
28. System.out.println("The exception has been encountered" + e);
29. }
30.
31. }
32.
33. System.out.println(Thread.currentThread().getName() + " thread has finished executing");
34. }
35. }
36.
37. public class IsDestroyedExample
38. {
39. // main method
40. public static void main(String argvs[]) throws SecurityException, InterruptedException
41. {
42. // creating the thread group
43. ThreadGroup tg = new ThreadGroup("the parent group");
44.
45. ThreadGroup tg1 = new ThreadGroup(tg, "the child group");
46.
47. ThreadNew th1 = new ThreadNew("the first", tg);
48. System.out.println("Starting the first");
73
49.
50. ThreadNew th2 = new ThreadNew("the second", tg);
51. System.out.println("Starting the second");
52.
53. if (tg.isDestroyed() == true)
54. {
55. System.out.println("The group has been destroyed.");
56. }
57. else
58. {
59. System.out.println("The group has not been destroyed.");
60. }
61.
62. }
63. }
Output:
74
Java Shutdown Hook
A special construct that facilitates the developers to add some code that has to be run
when the Java Virtual Machine (JVM) is shutting down is known as the Java shutdown
hook. The Java shutdown hook comes in very handy in the cases where one needs to
perform some special cleanup work when the JVM is shutting down. Note that handling
an operation such as invoking a special method before the JVM terminates does not work
using a general construct when the JVM is shutting down due to some external factors.
For example, whenever a kill request is generated by the operating system or due to
resource is not allocated because of the lack of free memory, then in such a case, it is not
possible to invoke the procedure. The shutdown hook solves this problem comfortably
by providing an arbitrary block of code.
Taking at a surface level, learning about the shutdown hook is straightforward. All one
has to do is to derive a class using the java.lang.Thread class, and then provide the code
for the task one wants to do in the run() method when the JVM is going to shut down.
For registering the instance of the derived class as the shutdown hook, one has to invoke
the method Runtime.getRuntime().addShutdownHook(Thread), whereas for removing the
already registered shutdown hook, one has to invoke the removeShutdownHook(Thread)
method.
In nutshell, the shutdown hook can be used to perform cleanup resources or save the
state when JVM shuts down normally or abruptly. Performing clean resources means
closing log files, sending some alerts, or something else. So if you want to execute some
code before JVM shuts down, use the shutdown hook.
75
o user presses ctrl+c on the command prompt
o System.exit(int) method is invoked
o user logoff
o user shutdown etc.
Syntax:
The object of the Runtime class can be obtained by calling the static factory method
getRuntime(). For example:
1. Runtime r = Runtime.getRuntime();
The removeShutdownHook(Thread hook) method
The removeShutdownHook() method of the Runtime class is invoked to remove the
registration of the already registered shutdown hooks.
Syntax:
True value is returned by the method, when the method successfully de-register the
registered hooks; otherwise returns false.
Factory method
The method that returns the instance of a class is known as factory method.
76
2. public void run(){
3. System.out.println("shut down hook task completed..");
4. }
5. }
6.
7. public class TestShutdown1{
8. public static void main(String[] args)throws Exception {
9.
10. Runtime r=Runtime.getRuntime();
11. r.addShutdownHook(new MyThread());
12.
13. System.out.println("Now main sleeping... press ctrl+c to exit");
14. try{Thread.sleep(3000);}catch (Exception e) {}
15. }
16. }
Output:
77
13. System.out.println("Now main sleeping... press ctrl+c to exit");
14. try{Thread.sleep(3000);}catch (Exception e) {}
15. }
16. }
Output:
FileName: RemoveHookExample.java
78
22. // registering the Msg object as the shutdown hook
23. Runtime.getRuntime().addShutdownHook(ms);
24.
25. // printing the current state of program
26. System.out.println("The program is beginning ...");
27.
28. // causing the thread to sleep for 2 seconds
29. System.out.println("Waiting for 2 seconds ...");
30. Thread.sleep(2000);
31.
32. // removing the hook
33. Runtime.getRuntime().removeShutdownHook(ms);
34.
35. // printing the message program is terminating
36. System.out.println("The program is terminating ...");
37. }
38. catch (Exception ex)
39. {
40. ex.printStackTrace();
41. }
42. }
43. }
Output:
Points to Remember
There are some important points to keep in mind while working with the shutdown hook.
No guarantee for the execution of the shutdown hooks: The first and the most important
thing to keep in mind is that there is no certainty about the execution of the shutdown
hook. In some scenarios, the shutdown hooks will not execute at all. For example, if the
JVM gets crashed due to some internal error, then there is no scope for the shutdown
79
hooks. When the operating system gives the SYSKILL signal, then also it is not possible
for the shutdown hooks to come into picture.
Note that when the application is terminated normally the shutdown hooks are called (all
threads of the application is finished or terminated). Also, when the operating system is
shut down or the user presses the ctrl + c the shutdown hooks are invoked.
Before completion, the shutdown hooks can be stopped forcefully: It is a special case of
the above discussed point. Whenever a shutdown hooks start to execute, one can
forcefully terminate it by shutting down the system. In this case, the operating system for
a specific amount of time. If the job is not done in that frame of time, then the system has
no other choice than to forcefully terminate the running hooks.
There can be more than one shutdown hooks, but there execution order is not
guaranteed: The JVM can execute the shutdown hooks in any arbitrary order. Even
concurrent execution of the shutdown hooks are also possible.
Within shutdown hooks, it is not allowed to unregister or register the shutdown hooks:
When the JVM initiates the shutdown sequence, one can not remove or add more any
existing shutdown hooks. If one tries to do so, the IllegalStateException is thrown by the
JVM.
The Runtime.halt() can stop the shutdown sequence that has been started: Only the
Runtime.halt(), which terminates the JVM forcefully, can stop the started shutdown
sequence, which also means that invoking the System.exit() method will not work within
a shutdown hook.
Security permissions are required when using shutdown hooks: If one is using the Java
Security Managers, then the Java code that is responsible for removing or adding the
shutdown hooks need to get the shutdown hooks permission at the runtime. If one
invokes the method without getting the permission in the secure environment, then it will
raise the SecurityException.
80
How to perform single task by multiple threads in
Java?
If you have to perform a single task by many threads, have only one run() method. For
example:
Output:
task one
task one
81
task one
Program of performing single task by multiple threads
FileName: TestMultitasking2.java
Output:
task one
task one
Note: Each thread run in a separate callstack.
82
How to perform multiple tasks by multiple threads
(multitasking in multithreading)?
If you have to perform multiple tasks by multiple threads,have multiple run() methods.For
example:
FileName: TestMultitasking3.java
Output:
83
task one
task two
Same example as above by anonymous class that extends
Thread class:
Program of performing two tasks by two threads
FileName: TestMultitasking4.java
1. class TestMultitasking4{
2. public static void main(String args[]){
3. Thread t1=new Thread(){
4. public void run(){
5. System.out.println("task one");
6. }
7. };
8. Thread t2=new Thread(){
9. public void run(){
10. System.out.println("task two");
11. }
12. };
13.
14.
15. t1.start();
16. t2.start();
17. }
18. }
Output:
task one
task two
Same example as above by anonymous class that implements
Runnable interface:
Program of performing two tasks by two threads
84
FileName: TestMultitasking5.java
1. class TestMultitasking5{
2. public static void main(String args[]){
3. Runnable r1=new Runnable(){
4. public void run(){
5. System.out.println("task one");
6. }
7. };
8.
9. Runnable r2=new Runnable(){
10. public void run(){
11. System.out.println("task two");
12. }
13. };
14.
15. Thread t1=new Thread(r1);
16. Thread t2=new Thread(r2);
17.
18. t1.start();
19. t2.start();
20. }
21. }
Output:
task one
task two
Printing even and odd numbers using two threads
To print the even and odd numbers using the two threads, we will use the synchronized
block and the notify() method. Observe the following program.
FileName: OddEvenExample.java
1. // Java program that prints the odd and even numbers using two threads.
2. // the time complexity of the program is O(N), where N is the number up to which we
85
3. // are displaying the numbers
4. public class OddEvenExample
5. {
6. // Starting the counter
7. int contr = 1;
8. static int NUM;
9. // Method for printing the odd numbers
10. public void displayOddNumber()
11. {
12. // note that synchronized blocks are necessary for the code for getting the desired
13. // output. If we remove the synchronized blocks, we will get an exception.
14. synchronized (this)
15. {
16. // Printing the numbers till NUM
17. while (contr < NUM)
18. {
19. // If the contr is even then display
20. while (contr % 2 == 0)
21. {
22. // handling the exception handle
23. try
24. {
25. wait();
26. }
27. catch (InterruptedException ex)
28. {
29. ex.printStackTrace();
30. }
31. }
32. // Printing the number
33. System.out.print(contr + " ");
34. // Incrementing the contr
35. contr = contr + 1;
36. // notifying the thread which is waiting for this lock
86
37. notify();
38. }
39. }
40. }
41. // Method for printing the even numbers
42. public void displayEvenNumber()
43. {
44. synchronized (this)
45. {
46. // Printing the number till NUM
47. while (contr < NUM)
48. {
49. // If the count is odd then display
50. while (contr % 2 == 1)
51. {
52. // handling the exception
53. try
54. {
55. wait();
56. }
57. catch (InterruptedException ex)
58. {
59. ex.printStackTrace();
60. }
61. }
62. // Printing the number
63. System.out.print(contr + " ");
64. // Incrementing the contr
65. contr = contr +1;
66. // Notifying to the 2nd thread
67. notify();
68. }
69. }
70. }
87
71. // main method
72. public static void main(String[] argvs)
73. {
74. // The NUM is given
75. NUM = 20;
76. // creating an object of the class OddEvenExample
77. OddEvenExample oe = new OddEvenExample();
78. // creating a thread th1
79. Thread th1 = new Thread(new Runnable()
80. {
81. public void run()
82. {
83. // invoking the method displayEvenNumber() using the thread th1
84. oe.displayEvenNumber();
85. }
86. });
87. // creating a thread th2
88. Thread th2 = new Thread(new Runnable()
89. {
90. public void run()
91. {
92. // invoking the method displayOddNumber() using the thread th2
93. oe.displayOddNumber();
94. }
95. });
96. // starting both of the threads
97. th1.start();
98. th2.start();
99. }
100. }
Output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
88
Java Garbage Collection
In java, garbage means unreferenced objects.
To do so, we were using free() function in C language and delete() in C++. But, in java it
is performed automatically. So, java provides better memory management.
89
1) By nulling a reference:
1. Employee e=new Employee();
2. e=null;
2) By assigning a reference to another:
1. Employee e1=new Employee();
2. Employee e2=new Employee();
3. e1=e2;//now the first object referred by e1 is available for garbage collection
3) By anonymous object:
1. new Employee();
finalize() method
The finalize() method is invoked each time before the object is garbage collected. This
method can be used to perform cleanup processing. This method is defined in Object
class as:
90
1. protected void finalize(){}
Note: The Garbage collector of JVM collects only those objects that are created by new
keyword. So if you have created any object without new, you can use finalize method
to perform cleanup processing (destroying remaining objects).
gc() method
The gc() method is used to invoke the garbage collector to perform cleanup processing.
The gc() is found in System and Runtime classes.
91
Important methods of Java Runtime class
Here you can use -s switch to shutdown system, -r switch to restart system and -t switch
to specify time delay.
92
3. Runtime.getRuntime().exec("shutdown -s -t 0");
4. }
5. }
93
4. System.out.println("Total Memory: "+r.totalMemory());
5. System.out.println("Free Memory: "+r.freeMemory());
6.
7. for(int i=0;i<10000;i++){
8. new MemoryTest();
9. }
10. System.out.println("After creating 10000 instance, Free Memory: "+r.freeMemory());
11. System.gc();
12. System.out.println("After gc(), Free Memory: "+r.freeMemory());
13. }
14. }
Total Memory: 100139008
Free Memory: 99474824
After creating 10000 instance, Free Memory: 99310552
After gc(), Free Memory: 100182832
94