Multithreading in Java
General
Two types of threads in an application:
- User Thread
- Daemon Thread
We can set different priorities to different Threads but it doesn’t guarantee that higher priority thread will execute first than lower priority thread.
volatile -控制caching
Create Thread
- Implementing Runnable Interface
- Extending Thread Class
Why Use Callable Future? Need Return Value.
Thread doesn’t return any value but what if we want our thread to do some processing and then return the result to our client program, check Java Callable Future.
1-Java Thread Example
Every java application has at least one thread – Main Thread.
Process
- Self contained execution environment
- Seen as a program / application
Thread
- Lightweight Process
- Less Resources to create and exists in the process
- Share Process Resources
Difference between Thread and Process
Java Threads Benefits
- Lightweight compared to processes, it takes less time and resource to create a thread
- Threads share their parent process data and code
- Context switching between threads is usually less expensive than between processes.
- Thread intercommunication is relatively easy than process communication.
Impementing Runnable Interface
- Implement
java.lang.Runnable
interface - Provide implementation in
public void run()
method. - Create a Thread object by passing object of this runnable class
- Then call
start()
method to execute therun()
method in a separate thread.
package com.journaldev.threads;
public class HeavyWorkRunnable implements Runnable {
@Override
public void run() {
System.out.println("Doing heavy processing - START "+Thread.currentThread().getName());
try {
Thread.sleep(1000);
//Get database connection, delete unused data from DB
doDBProcessing();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Doing heavy processing - END "+Thread.currentThread().getName());
}
private void doDBProcessing() throws InterruptedException {
Thread.sleep(5000);
}
}
Extending Thread Class
- Extend java.lang.Thread class to create our own java thread class
- Override
run()
method. - Create it’s object and call
start()
method to execute our custom java thread class run method.
package com.journaldev.threads;
public class MyThread extends Thread {
public MyThread(String name) {
super(name);
}
@Override
public void run() {
System.out.println("MyThread - START "+Thread.currentThread().getName());
try {
Thread.sleep(1000);
//Get database connection, delete unused data from DB
doDBProcessing();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("MyThread - END "+Thread.currentThread().getName());
}
private void doDBProcessing() throws InterruptedException {
Thread.sleep(5000);
}
}
//Here is a test program showing how to create a java thread and execute it.
package com.journaldev.threads;
public class ThreadRunExample {
public static void main(String[] args){
Thread t1 = new Thread(new HeavyWorkRunnable(), "t1");
Thread t2 = new Thread(new HeavyWorkRunnable(), "t2");
System.out.println("Starting Runnable threads");
t1.start();
t2.start();
System.out.println("Runnable Threads has been started");
Thread t3 = new MyThread("t3");
Thread t4 = new MyThread("t4");
System.out.println("Starting MyThreads");
t3.start();
t4.start();
System.out.println("MyThreads has been started");
}
}
Runnable vs Thread
- If your class provides more functionality rather than just running as Thread, you should implement Runnable interface to provide a way to run it as Thread.
- If your class only goal is to run as Thread, you can extend Thread class.
- Implementing Runnable is preferred because java supports implementing multiple interfaces.
2-Thread.sleep in Java
Thread.sleep()
method can be used to pause the execution of current thread for specified time in milliseconds.
Thread Sleep Example
//Here is a simple program where Thread.sleep() is used to pause the main thread execution for 2 seconds.
package com.journaldev.threads;
public class ThreadSleep {
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
Thread.sleep(2000);
System.out.println("Sleep time in ms = "+(System.currentTimeMillis()-start));
}
}
Thread Sleep Important Points
- It always pause the current thread execution.
- The actual time thread sleeps before waking up and start execution depends on system timers and schedulers. For a quiet system, the actual time for sleep is near to the specified sleep time but for a busy system it will be little bit more.
- Thread sleep doesn’t lose any monitors or locks current thread has acquired.
- Any other thread can interrupt the current thread in sleep, in that case InterruptedException is thrown.
How Thread Sleep Works
Thread.sleep()
interacts with the thread scheduler
to put the current thread in wait state
for specified period of time. Once the wait time is over, thread state is changed to runnable state
and wait for the CPU for further execution. So the actual time that current thread sleep depends on the thread scheduler that is part of operating system.
3-Java Thread Join
Java Thread join method can be used to pause the current thread execution until unless the specified thread is dead. There are three overloaded join functions.
- public final void join(): This java thread join method puts the current thread on wait until the thread on which it’s called is dead. If the thread is interrupted, it throws InterruptedException.
- public final synchronized void join(long millis): This java thread join method is used to wait for the thread on which it’s called to be dead or wait for specified milliseconds. Since thread execution depends on OS implementation, it doesn’t guarantee that the current thread will wait only for given time.
- public final synchronized void join(long millis, int nanos): This java thread join method is used to wait for thread to die for given milliseconds plus nanoseconds.
/*
Here is a simple example showing usage of Thread join methods. The goal of the program is to make sure main is the last thread to finish and third thread starts only when first one is dead.
*/
package com.journaldev.threads;
public class ThreadJoinExample {
public static void main(String[] args) {
Thread t1 = new Thread(new MyRunnable(), "t1");
Thread t2 = new Thread(new MyRunnable(), "t2");
Thread t3 = new Thread(new MyRunnable(), "t3");
t1.start();
//start second thread after waiting for 2 seconds or if it's dead
try {
t1.join(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
//start third thread only when first thread is dead
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
t3.start();
//let all threads finish execution before finishing main thread
try {
t1.join();
t2.join();
t3.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("All threads are dead, exiting main thread");
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("Thread started:::"+Thread.currentThread().getName());
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread ended:::"+Thread.currentThread().getName());
}
}
/*
Thread started:::t1
Thread started:::t2
Thread ended:::t1
Thread started:::t3
Thread ended:::t2
Thread ended:::t3
All threads are dead, exiting main thread
*/
4-Java Thread States
Below diagram shows different states of thread life cycle in java. We can create a thread in java and start it but how the thread states change from Runnable to Running to Blocked depends on the OS implementation of thread scheduler and java doesn’t have full control on that.
New
When we create a new Thread object using new
operator, thread state is New Thread
. At this point, thread is not alive and it’s a state internal to Java programming.
Runnable
When we call start()
function on Thread object, it’s state is changed to Runnable. The control is given to Thread scheduler to finish it’s execution. Whether to run this thread instantly or keep it in runnable thread pool before running, depends on the OS implementation of thread scheduler.
Running
When thread is executing, it’s state is changed to Running. Thread scheduler picks one of the thread from the runnable thread pool and change it’s state to Running. Then CPU starts executing this thread. A thread can change state to Runnable, Dead or Blocked from running state depends on time slicing, thread completion of run() method or waiting for some resources.
Blocked / Waiting
A thread can be waiting for other thread to finish using thread join
or it can be waiting for some resources to available. For example producer consumer problemor waiter notifier implementation or IO resources, then it’s state is changed to Waiting. Once the thread wait state is over, it’s state is changed to Runnable and it’s moved back to runnable thread pool.
Dead
Once the thread finished executing, it’s state is changed to Dead and it’s considered to be not alive.
5-Java Thread wait, notify and notifyAll
The Object class in java contains three final methods that allows threads to communicate about the lock status of a resource. These methods are wait(), notify() and notifyAll().
The current thread which invokes these methods on any object should have the object monitor else it throws java.lang.IllegalMonitorStateException exception.
Wait
Object wait
methods has three variance, one which waits indefinitely for any other thread to call notify or notifyAll method on the object to wake up the current thread. Other two variances puts the current thread in wait for specific amount of time before they wake up.
Notify
notify method wakes up only one thread waiting on the object and that thread starts execution. So if there are multiple threads waiting for an object, this method will wake up only one of them. The choice of the thread to wake depends on the OS implementation of thread management.
NotifyAll
notifyAll method wakes up all the threads waiting on the object, although which one will process first depends on the OS implementation.
These methods can be used to implement producer consumer problem where consumer threads are waiting for the objects in Queue and producer threads put object in queue and notify the waiting threads.
Let’s see an example where multiple threads work on the same object and we use wait, notify and notifyAll methods.
Example
Message
//A java bean class on which threads will work and call wait and notify methods.
package com.journaldev.concurrency;
public class Message {
private String msg;
public Message(String str){
this.msg=str;
}
public String getMsg() {
return msg;
}
public void setMsg(String str) {
this.msg=str;
}
}
Waiter
A class that will wait for other threads to invoke notify methods to complete it’s processing. Notice that Waiter thread is owning monitor on Message object using synchronized block.
package com.journaldev.concurrency;
public class Waiter implements Runnable{
private Message msg;
public Waiter(Message m){
this.msg=m;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
synchronized (msg) {
try{
System.out.println(name+" waiting to get notified at time:"+System.currentTimeMillis());
msg.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(name+" waiter thread got notified at time:"+System.currentTimeMillis());
//process the message now
System.out.println(name+" processed: "+msg.getMsg());
}
}
}
Notifier
A class that will process on Message object and then invoke notify method to wake up threads waiting for Message object. Notice that synchronized block is used to own the monitor of Message object.
package com.journaldev.concurrency;
public class Notifier implements Runnable {
private Message msg;
public Notifier(Message msg) {
this.msg = msg;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name+" started");
try {
Thread.sleep(1000);
synchronized (msg) {
msg.setMsg(name+" Notifier work done");
msg.notify();
// msg.notifyAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
WaitNotifyTest
Test class that will create multiple threads of Waiter and Notifier and start them.
package com.journaldev.concurrency;
public class WaitNotifyTest {
public static void main(String[] args) {
Message msg = new Message("process it");
Waiter waiter = new Waiter(msg);
new Thread(waiter,"waiter").start();
Waiter waiter1 = new Waiter(msg);
new Thread(waiter1, "waiter1").start();
Notifier notifier = new Notifier(msg);
new Thread(notifier, "notifier").start();
System.out.println("All the threads are started");
}
}
6-Java Thread Safety and Java Synchronization
Different Ways to make program thread safe.
- Synchronization is the easiest and most widely used tool for thread safety in java.
- Use of Atomic Wrapper classes from
*java.util.concurrent.atomic*
package. For example AtomicInteger - Use of locks from
*java.util.concurrent.locks*
package. - Using thread safe collection classes, check this post for usage of ConcurrentHashMap for thread safety.
- Using volatile keyword with variables to make every thread read the data from memory, not read from thread cache.
Java Synchronized
JVM guarantees that synchronized code will be executed by only one thread at a time. java keyword synchronized is used to create synchronized code and internally it uses locks on Object or Class to make sure only one thread is executing the synchronized code.
- Java synchronization works on locking and unlocking of resource, before any thread enters into synchronized code, it has to acquire lock on the Object and when code execution ends, it unlocks the resource that can be locked by other threads. In the mean time other threads are in wait state to lock the synchronized resource.
- We can use synchronized keyword in two ways, one is to make a complete method synchronized and other way is to create synchronized block.
- When a method is synchronized, it locks the Object, if method is static it locks the Class, so it's always best practice to use synchronized block to lock the only sections of method that needs synchronization.
- While creating synchronized block, we need to provide the resource on which lock will be acquired, it can be XYZ.class or any Object field of the class.
synchronized(this)
will lock the Object before entering into the synchronized block.- You should use the lowest level of locking, for example if there are multiple synchronized block in a class and one of them is locking the Object, then other synchronized blocks will also be not available for execution by other threads. When we lock an Object, it acquires lock on all the fields of the Object.
- Java Synchronization provides data integrity on the cost of performance, so it should be used only when it's absolutely necessary.
- Java Synchronization works only in the same JVM, so if you need to lock some resource in multiple JVM environment, it will not work and you might have to look after some global locking mechanism.
- Java Synchronization could result in deadlocks, check this post about deadlock in java and how to avoid them.
- Java synchronized keyword cannot be used for constructors and variables.
- It is preferable to create a dummy private Object to use for synchronized block, so that it's reference can't be changed by any other code. For example if you have a setter method for Object on which you are synchronizing, it's reference can be changed by some other code leads to parallel execution of the synchronized block.
- We should not use any object that is maintained in a constant pool, for example String should not be used for synchronization because if any other code is also locking on same String, it will try to acquire lock on the same reference object from String pool and even though both the codes are unrelated, they will lock each other.
Example
//dummy object variable for synchronization
private Object mutex=new Object();
...
//using synchronized block to read, increment and update count value synchronously
synchronized (mutex) {
count++;
}
7-Java Exception in Thread Main
Tips:
- Same JRE version is used to compile and run the java program
- You are running java class from the classes directory and package is provided as directory.
- Your java classpath is set properly to include all the dependency classes
- You are using only file name without .class extension while running a java program
- Java class main method syntax is correct
Exception in thread main java.lang.UnsupportedClassVersionError
This exception comes when your java class is compiled from another JDK version and you are trying to run it from another java version.
The reason for this exception is that we can’t compile a java source file from higher version and then run it on lower version of JRE.
Exception in thread main java.lang.NoClassDefFoundError
Exception in thread main java.lang.NoSuchMethodError: main
This exception comes when you are trying to run a class that doesn’t have main
method. In Java 7, the error message is changed to make it more clear.
Exception in thread “main” java.lang.ArithmeticException
8-Thread Safety in Singleton Class
In real world applications, resources like Database connections or Enterprise Information Systems (EIS) are limited and should be used wisely to avoid any resource crunch. To achieve this, we can implement Singleton design pattern to create a wrapper class around the resource and limit the number of object created at runtime to one.
Steps to create a singleton class:
- Override the private constructor to avoid any new object creation with new operator.
- Declare a private static instance of the same class
- Provide a public static method that will return the singleton class instance variable. If the variable is not initialized then initialize it or else simply return the instance variable.
package com.journaldev.designpatterns;
public class ASingleton {
private static ASingleton instance = null;
private ASingleton() {
}
public static ASingleton getInstance() {
if (instance == null) {
instance = new ASingleton();
}
return instance;
}
}
/*
In the above code, getInstance() method is not thread safe. Multiple threads can access it at the same time and for the first few threads when the instance variable is not initialized, multiple threads can enters the if loop and create multiple instances and break our singleton implementation.
*/
Three ways to achieve thread safety.
考虑:
- 是否安全
- 是否Lazy initialization
- 是否可以传参
- Overhead是否最小
1-Create the instance variable at the time of class loading
Pros:
- Thread safety without synchronization
- Easy to implement
Cons:
- Early creation of resource that might not be used in the application.
- The client application can’t pass any argument, so we can’t reuse it. For example, having a generic singleton class for database connection where client application supplies database server properties.
2-Synchronize the getInstance() method
Pros:
- Thread safety is guaranteed.
- Client application can pass parameters
- Lazy initialization achieved
Cons:
- Slow performance because of locking overhead.
- Unnecessary synchronization that is not required once the instance variable is initialized.
3-Use synchronized block inside the if loop and volatile variable
Pros:
- Thread safety is guaranteed
- Client application can pass arguments
- Lazy initialization achieved
- Synchronization overhead is minimal and applicable only for first few threads when the variable is null.
Cons:
- Extra if condition
Looking at all the three ways to achieve thread safety, I think third one is the best option and in that case the modified class will look like:
package com.journaldev.designpatterns;
public class ASingleton {
private static volatile ASingleton instance;
private static Object mutex = new Object();
private ASingleton() {
}
public static ASingleton getInstance() {
ASingleton result = instance;
if (result == null) {
synchronized (mutex) {
result = instance;
if (result == null)
instance = result = new ASingleton();
}
}
return result;
}
}
/*
Local variable result seems unnecessary. But it’s there to improve performance of our code. In cases where instance is already initialized (most of the time), the volatile field is only accessed once (due to “return result;” instead of “return instance;”). This can improve the method’s overall performance by as much as 25 percent.
*/
9-Daemon Thread in Java
When a thread is marked as daemon thread, JVM doesn’t wait it to finish to terminate the program. As soon as all the user threads are finished, JVM terminates the program as well as all the associated daemon threads.
Thread.setDaemon(true)
is used to create a daemon thread in java. This method should be invoked before the thread is started otherwise it will throw IllegalThreadStateException
.
We can check if a thread is daemon thread or not by calling isDaemon()
method on it.
Another point is that when a thread is started, it inherits the daemon status of it’s parent thread.
Example
public class JavaDaemonThread {
public static void main(String[] args) throws InterruptedException {
Thread dt = new Thread(new DaemonThread(), "dt");
dt.setDaemon(true);
dt.start();
//continue program
Thread.sleep(30000);
System.out.println("Finishing program");
}
}
class DaemonThread implements Runnable{
@Override
public void run() {
while(true){
processSomething();
}
}
private void processSomething() {
try {
System.out.println("Processing daemon thread");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
When main method is finished, the program terminates and daemon thread is also shut down by JVM.
If we don’t set the “dt” thread to be run as daemon thread, the program will never terminate even after main thread is finished it’s execution. Notice that DaemonThread
is having a while true loop with thread sleep, so it will never terminate on it’s own.
Daemon Thread Usage
Usually we create a daemon thread for functionalities that are not critical to system. For example logging thread or monitoring thread to capture the system resource details and their state. If you are not okay will a thread being terminated, don’t create it as a daemon thread.
Also it’s better to avoid daemon threads for IO operations because it can cause resource leak when program just terminates and resources are not closed properly.
10-Java Thread Local
Java ThreadLocal is used to create thread local variables. We know that all threads of an Object share it’s variables, so the variable is not thread safe. We can use synchronization for thread safety but if we want to avoid synchronization, we can use ThreadLocal
variables.
Every thread has it’s own ThreadLocal
variable and they can use it’s get()
and set()
methods to get the default value or change it’s value local to Thread.
ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread.
Example
public class ThreadLocalExample implements Runnable{
// SimpleDateFormat is not thread-safe, so give one to each thread
private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
@Override
protected SimpleDateFormat initialValue()
{
return new SimpleDateFormat("yyyyMMdd HHmm");
}
};
public static void main(String[] args) throws InterruptedException {
ThreadLocalExample obj = new ThreadLocalExample();
for(int i=0 ; i<10; i++){
Thread t = new Thread(obj, ""+i);
Thread.sleep(new Random().nextInt(1000));
t.start();
}
}
@Override
public void run() {
System.out.println("Thread Name= "+Thread.currentThread().getName()+" default Formatter = "+formatter.get().toPattern());
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
//formatter pattern is changed here by thread, but it won't reflect to other threads
formatter.set(new SimpleDateFormat());
System.out.println("Thread Name= "+Thread.currentThread().getName()+" formatter = "+formatter.get().toPattern());
}
}
11-Java Thread Dump
Java Thread dump provides the current threads information for the program. Java Thread dump provides useful information to analyze performance issues with the application. You can use thread dump to find and fix deadlock situations. This post explains different methods that can be used to generate thread dump in java.
12-How to Analyze Deadlock and avoid it in Java
Deadlock is a situation where multiple threads are waiting for each other to release resources causing cyclic dependency. This article discusses about the situation in which we can get deadlock in a java program. How we can use Thread dump to find the deadlock and best practices to avoid deadlock in java program.
How to Avoid Deadlock in Java
Avoid Nested Locks: This is the most common reason for deadlocks, avoid locking another resource if you already hold one. It’s almost impossible to get deadlock situation if you are working with only one object lock. For example, here is the another implementation of run() method without nested lock and program runs successfully without deadlock situation.
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name + " acquiring lock on "+obj1);
synchronized (obj1) {
System.out.println(name + " acquired lock on "+obj1);
work();
System.out.println(name + " acquiring lock on "+obj2);
synchronized (obj2) {
System.out.println(name + " acquired lock on "+obj2);
work();
}
System.out.println(name + " released lock on "+obj2);
}
System.out.println(name + " released lock on "+obj1);
System.out.println(name + " finished execution.");
}
Lock Only What is Required: You should acquire lock only on the resources you have to work on, for example in above program I am locking the complete Object resource but if we are only interested in one of it’s fields, then we should lock only that specific field not complete object.
Avoid waiting indefinitely: You can get deadlock if two threads are waiting for each other to finish indefinitely using thread join. If your thread has to wait for another thread to finish, it’s always best to use join with maximum time you want to wait for thread to finish.
13-Java Timer Thread
This post explains how we can use Java Timer and TimerTask classes to create jobs to run at scheduled interval, an example program showing it’s usage and how we can cancel the timer.
Java java.util.Timer is a utility class that can be used to schedule a thread to be executed at certain time in future. Java Timer class can be used to schedule a task to be run one-time or to be run at regular intervals.
java.util.TimerTask is an abstract class that implements Runnable interface and we need to extend this class to create our own TimerTask that can be scheduled using java Timer class.
Java Timer class is thread safe and multiple threads can share a single Timer object without need for external synchronization. Timer class uses java.util.TaskQueue to add tasks at given regular interval and at any time there can be only one thread running the TimerTask, for example if you are creating a Timer to run every 10 seconds but single thread execution takes 20 seconds, then Timer object will keep adding tasks to the queue and as soon as one thread is finished, it will notify the queue and another thread will start executing.
Java Timer class uses Object wait and notify methods to schedule the tasks.
Example
package com.journaldev.threads;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class MyTimerTask extends TimerTask {
@Override
public void run() {
System.out.println("Timer task started at:"+new Date());
completeTask();
System.out.println("Timer task finished at:"+new Date());
}
private void completeTask() {
try {
//assuming it takes 20 secs to complete the task
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String args[]){
TimerTask timerTask = new MyTimerTask();
//running timer task as daemon thread
Timer timer = new Timer(true);
timer.scheduleAtFixedRate(timerTask, 0, 10*1000);
System.out.println("TimerTask started");
//cancel after sometime
try {
Thread.sleep(120000);
} catch (InterruptedException e) {
e.printStackTrace();
}
timer.cancel();
System.out.println("TimerTask cancelled");
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/*
Notice that one thread execution will take 20 seconds but Java Timer object is scheduled to run the task every 10 seconds. Here is the output of the program:
TimerTask started
Timer task started at:Wed Dec 26 19:16:39 PST 2012
Timer task finished at:Wed Dec 26 19:16:59 PST 2012
Timer task started at:Wed Dec 26 19:16:59 PST 2012
Timer task finished at:Wed Dec 26 19:17:19 PST 2012
Timer task started at:Wed Dec 26 19:17:19 PST 2012
Timer task finished at:Wed Dec 26 19:17:39 PST 2012
Timer task started at:Wed Dec 26 19:17:39 PST 2012
Timer task finished at:Wed Dec 26 19:17:59 PST 2012
Timer task started at:Wed Dec 26 19:17:59 PST 2012
Timer task finished at:Wed Dec 26 19:18:19 PST 2012
Timer task started at:Wed Dec 26 19:18:19 PST 2012
TimerTask cancelled
Timer task finished at:Wed Dec 26 19:18:39 PST 2012
The output confirms that if a task is already executing, Timer will wait for it to finish and once finished, it will start again the next task from the queue.
*/
Java Timer object can be created to run the associated tasks as a daemon thread. Timer cancel() method is used to terminate the timer and discard any scheduled tasks, however it doesn’t interfere with the currently executing task and let it finish. If the timer is run as daemon thread, whether we cancel it or not, it will terminate as soon as all the user threads are finished executing.
Timer class contains several schedule() methods to schedule a task to run once at given date or after some delay. There are several scheduleAtFixedRate() methods to run a task periodically with certain interval.
14-Java Producer Consumer Problem
Before Java 5, producer-consumer problem can be solved using wait() and notify() methods but introduction of BlockingQueue has made it very easy. Learn how we can use BlockingQueue to solve producer consumer problem in java.
java.util.concurrent.BlockingQueue
is a java Queue that support operations that wait for the queue to become non-empty when retrieving and removing an element, and wait for space to become available in the queue when adding an element.
Java BlockingQueue doesn’t accept null
values and throw NullPointerException
if you try to store null value in the queue.
Java BlockingQueue implementations are thread-safe. All queuing methods are atomic in nature and use internal locks or other forms of concurrency control.
Java provides several BlockingQueue implementations such as ArrayBlockingQueue
, LinkedBlockingQueue
, PriorityBlockingQueue
, SynchronousQueue
etc.
While implementing producer consumer problem in BlockingQueue, we will use ArrayBlockingQueue implementation. Following are some important methods you should know.
put(E e)
: This method is used to insert elements to the queue. If the queue is full, it waits for the space to be available.E take()
: This method retrieves and remove the element from the head of the queue. If queue is empty it waits for the element to be available.
15-Java Thread Pool
Java Thread Pool is a collection of worker threads waiting to process jobs. Java 5 introduction of Executor framework has made it very easy to create thread pool in java using Executors
and ThreadPoolExecutor
classes. Learn how to use them to create thread pool in java.
Java thread pool manages the pool of worker threads, it contains a queue that keeps tasks waiting to get executed. We can use ThreadPoolExecutor
to create thread pool in java.
Java thread pool manages the collection of Runnable threads and worker threads execute Runnable from the queue.
package com.journaldev.threadpool;
public class WorkerThread implements Runnable {
private String command;
public WorkerThread(String s){
this.command=s;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" Start. Command = "+command);
processCommand();
System.out.println(Thread.currentThread().getName()+" End.");
}
private void processCommand() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public String toString(){
return this.command;
}
}
ExecutorService Example
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SimpleThreadPool {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
Runnable worker = new WorkerThread("" + i);
executor.execute(worker);
}
executor.shutdown();
while (!executor.isTerminated()) {
}
System.out.println("Finished all threads");
}
}
/*
In above program, we are creating fixed size thread pool of 5 worker threads. Then we are submitting 10 jobs to this pool, since the pool size is 5, it will start working on 5 jobs and other jobs will be in wait state, as soon as one of the job is finished, another job from the wait queue will be picked up by worker thread and get's executed.
*/
ThreadPoolExecutor Example
Executors class provide simple implementation of ExecutorService using ThreadPoolExecutor but ThreadPoolExecutor provides much more feature than that. We can specify the number of threads that will be alive when we create ThreadPoolExecutor instance and we can limit the size of thread pool and create our own RejectedExecutionHandler implementation to handle the jobs that can't fit in the worker queue.
ThreadPoolExecutor
provides several methods using which we can find out the current state of executor, pool size, active thread count and task count. So I have a monitor thread that will print the executor information at certain time interval.
16-Java Callable Future
Sometimes we wish Thread could return values that we can use. Java 5 Callable can be used in that case that is similar as Runnable interface. We can use Executor framework to execute Callable tasks.
Java Callable
Java Callable interface use Generic to define the return type of Object. Executors class provide useful methods to execute Java Callable in a thread pool. Since callable tasks run in parallel, we have to wait for the returned Object.
Java Future
Java Callable tasks return java.util.concurrent.Future object. Using Java Future object, we can find out the status of the Callable task and get the returned Object. It provides get() method that can wait for the Callable to finish and then return the result.
Java Future provides cancel() method to cancel the associated Callable task. There is an overloaded version of get() method where we can specify the time to wait for the result, it’s useful to avoid current thread getting blocked for longer time. There are isDone() and isCancelled() methods to find out the current status of associated Callable task.
Here is a simple example of Java Callable task that returns the name of thread executing the task after one second. We are using Executor framework to execute 100 tasks in parallel and use Java Future to get the result of the submitted tasks.
package com.journaldev.threads;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
Thread.sleep(1000);
//return the thread name executing this callable task
return Thread.currentThread().getName();
}
public static void main(String args[]){
//Get ExecutorService from Executors utility class, thread pool size is 10
ExecutorService executor = Executors.newFixedThreadPool(10);
//create a list to hold the Future object associated with Callable
List<Future<String>> list = new ArrayList<Future<String>>();
//Create MyCallable instance
Callable<String> callable = new MyCallable();
for(int i=0; i< 100; i++){
//submit Callable tasks to be executed by thread pool
Future<String> future = executor.submit(callable);
//add Future to the list, we can get return value using Future
list.add(future);
}
for(Future<String> fut : list){
try {
//print the return value of Future, notice the output delay in console
// because Future.get() waits for task to get completed
System.out.println(new Date()+ "::"+fut.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
//shut down the executor service now
executor.shutdown();
}
}
/*
Mon Dec 31 20:40:15 PST 2012::pool-1-thread-1
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-2
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-3
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-4
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-5
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-6
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-7
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-8
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-9
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-10
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-2
...
Once we execute the above program, you will notice the delay in output because java Future get() method waits for the java callable task to complete. Also notice that there are only 10 threads executing these tasks.
*/
6-Countdown Latches
CountDownLatch latch - new CountDownLatch(3);
latch.countDown()
latch.await();
Thread Safe
10-Re-Entrant Locks
Lock lock = new ReentrantLock();
lock.lock();
lock.unlock();
Condition cond = lock.newCondition();
condition.await();
cond.signal();
11DeadLock
tryLock();
unlock
12- Semaphores
Semaphore sem = new Semaphore(1);
sem.acquire();
sem.release();s
sem.availablePermits()
14-Interrupting Threads
t1.interrupt()
thread pool cancel