ZOFTINO.COM android and web dev tutorials

Java Multithreading and Concurrency

Running programs parallel improves application’s responsiveness. Computing resources which are allocated for a program can be used for running sub programs, when one sub program is idle, for example waiting for response from server or OS, one of the other sub programs can run utilizing idle computing resources. In this tutorial, you can learn how to write Java programs which can run parallel using threads.

Table of Contents

Threads

When you run a java application, JVM starts as a process with a single thread called main thread. A process is an execution environment having its own runtime resources such as memory. Threads exist within the process and they use and share resources allocated for the process in which they exist. Main thread can create multiple threads with each thread containing the code that it needs to run.

You can create a thread by extending the Thread class, implementing run() method and calling start() on the thread object.

public class CouponProvider extends Thread{
	@Override
	public void run() {
		String offers = getCouponOffers();
		System.out.println(offers);
	}
	
	public String getCouponOffers() {
		return "upto 40% off on bags,"
				+ "flat60% off on t shirts";
	}
}
public static void main(String[] args) {			
	new CouponProvider().start();
}

You can also create a thread by implementing Runnable interface, passing an instance of it to the constructor of Thread class and calling the start() method on the thread object. The run method of the runnable object contains the code which is executed by the thread.

public class CashbackProvider implements Runnable{
	@Override
	public void run() {
		String offers = getCashbackOffers();
		System.out.println(offers);
		System.out.println("child thread "
				+Thread.currentThread().getId());
	}
	
	public String getCashbackOffers() {
		return "upto 2% cashback on fashion,"
				+ "get 3% cashback on mobiles";
	}
}

Output:

main thread 1
upto 2% cashback on fashion,get 3% cashback on mobiles
child thread 10

The advantage of using Runnable interface instead of extending Thread is that code is separated from the thread which executes it using Runnable interface. Also, you can use existing classes by extending them to create runnable object. This is not possible when you create a thread by extending the Thread class.

public class CashbackProvider extends OfferProvider
					implements Runnable {
	@Override
	public void run() {
		//use methods of OfferProvider
		//do something else..
	}
}

A thread can be made to suspend the execution for a specified time using sleep method of the thread object so that computing resources can be made available to other threads. Following code makes the current thread to sleep for 100 milliseconds.

		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {

		}

To access the current thread in which the code is running, you can call currentThread static method of Thread class.

String threadName = Thread.currentThread().getName();

Other static methods that Thread provides are activeCount(), gives the number of active threads in current thread’s thread group, dumpStack(), prints stack trace of current thread to error stream, enumerate(), gives an array of active threads which exist in the current thread’s thread group and its sub groups. Following example gets all active threads in the current thread’s thread group and prints name, priority and state of each thread.

		Thread[] threads = new Thread[Thread.activeCount()];
		Thread.enumerate(threads);
		for(Thread th :  threads) {
			System.out.println("Thread name "+th.getName());
			System.out.println("Thread priority "+th.getPriority());
			System.out.println("Thread state "+th.getState());			
		}

Thread Interruption

A thread can be interrupted meaning asked to stop what it is doing by calling interrupt method on the thread object. After interrupt method is invoked on a thread object, if the code being executed calls any of the methods which throw InterruptedException such as sleep() and join(), then the exception will be thrown and interrupt status will be cleared. To terminate the thread, you need add return statement in the exception handler.

	public static void main(String[] args) {		
		
		Thread one = new Thread(new Runnable() {
			@Override
			public void run() {
				for(int i=0; i< 50; i++) {
					System.out.println(""+i);
					
					try {
						Thread.sleep(20);
					} catch (InterruptedException e) {
						System.out.println("thread interrupted");
						return;
					}
				}				
			}
			
		});
		
		one.start();

		try {
			Thread.sleep(120);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		//interrupt thread one
		one.interrupt();
	}

If the code doesn’t call methods which throw InterruptedException, there should be a frequent check for interrupt signal using isInterruped() method of the thread object and return if interrupt signal exist. Method isInterruped() returns true if the thread is interrupted. To clear the interrupted signal for the current thread, you can use static interrupted() method of Thread. This method return true if interrupt status is set for the current thread and clears the status.

	for(int i=0; i< 50; i++) {
		System.out.println(""+i);
		
		if(Thread.currentThread().isInterrupted()) {
			System.out.println("thread interrupted");
		}
		
		if(Thread.interrupted()) {
			return;
		}
	}

Pause Current Thread using Join

Current thread can be made to wait till all other threads are done with execution by calling join() method on those threads which current thread needs to wait for them to complete. In the following example, main thread waits for the other thread to complete.

		Thread one = new Thread(new Runnable() {
			@Override
			public void run() {
				for(int i=0; i< 5; i++) {
					System.out.println("thread one "+i);
				}
			}			
		});		
		
		one.start();
		try {
			one.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		System.out.println("done starting the thread");

Ouput:

thread one 0
thread one 1
thread one 2
thread one 3
thread one 4
done starting the thread

Without join() call, output for the same program:

done starting the thread
thread one 0
thread one 1
thread one 2
thread one 3
thread one 4

Synchronization

If there are shared fields or objects among multiple threads, thread interference and memory consistency issues can arise. These issues lead to corrupt or inconsistent data. If you run the following example few times, there is a possibility that it will print different values. That is because sometime updates made to totalPrice field of cart object by thread one may be overwritten by thread two.

	public static void main(String[] args) {	
		
		Cart cart = new Cart();
		
		Thread tOne = new Thread(new Runnable() {
			@Override
			public void run() {
				for(int i=0; i< 5; i++) {
					cart.addToTotalPrice(i*213);

				}
			}			
		});		
		
		Thread tTwo = new Thread(new Runnable() {
			@Override
			public void run() {
				for(int i=0; i< 5; i++) {
					cart.addToTotalPrice(i*113);
				}
			}			
		});	
		
		tOne.start();
		tTwo.start();

		System.out.println("total cart price "+cart.getTotalPrice());
	}
public class Cart {
	private double totalPrice;

	public double getTotalPrice() {
		return totalPrice;
	}

	public void addToTotalPrice(double itemPrice) {
		totalPrice = totalPrice + itemPrice;
	}	
}

Thread interference and memory consistency issues can be solved using synchronization. Synchronization solves these issues by allowing only one thread at a time to access the fields of an object using intrinsic lock associated with the object. When a thread needs to access fields of an object, it acquires the object’s intrinsic lock, runs the code and releases the lock when it is done accessing the fields. Intrinsic lock of an object is acquired when a thread enters a synchronized method. It releases the lock when it returns from the synchronized method.

public class Cart {
	private double totalPrice;

	public double getTotalPrice() {
		return totalPrice;
	}

	public synchronized void addToTotalPrice(double itemPrice) {
		totalPrice = totalPrice + itemPrice;
	}	
}

Now if you run the same program with new version of Cart class above containing synchronized method, it will always print correct value.

Synchronized Block

The problem with synchronized method is that if an object contains more than one synchronized methods, only one thread can access these methods at a time, other threads have to wait for the object’s intrinsic lock to be released by the thread which own it, this is true even if other threads try to access different synchronized method of the object than what first thread is accessing.

To prevent blocking, synchronized blocks can be used. Synchronized blocks block threads where needed in the methods instead of blocking entire method. In the case of synchronized blocks, intrinsic lock of a different object is used and the object needs to be supplied to the block. This way if data is not shared among different synchronized blocks in a class, multiple synchronized blocks can be executed by different threads at the same time using locks of different objects.

public class Cart {
	private double totalPrice;
	private int itemCount;

	private Object objOne = new Object();
	private Object objTwo = new Object();

	public double getTotalPrice() {
		return totalPrice;
	}

	public void addToTotalPrice(double itemPrice) {
		synchronized(objOne) { 
			totalPrice = totalPrice + itemPrice;
		}
	}	

	public void addItems(int i) {
		synchronized(objTwo) { 
			itemCount = itemCount + i;
		}
	}
}

Synchronization Concurrency Issues

Using synchronization, corrupt and inconsistent data can be avoided. But you may still end up facing other issues caused by multiple threads accessing shared fields or waiting for locks. These issues are deadlock, starvation and livelock.

Deadlock

One of the issues caused by synchronization is deadlock. A deadlock scenario happens when a thread acquires intrinsic lock of object A by accessing one of the synchronized methods and second thread acquires intrinsic lock of object B, then the first thread waits for the lock of object B and second thread waits for the lock of object A. This needs to be prevented by proper design and coding. Following example runs forever due to deadlock issue.

	public static void main(String[] args) {	
		
		Cart c = new Cart();
		Tax t = new Tax();
		
		Thread tOne = new Thread(new Runnable() {
			@Override
			public void run() {
				for(int i=0; i< 5; i++) {
					c.addToTotalPrice(i*213, t);
				}
			}			
		});		
		
		Thread tTwo = new Thread(new Runnable() {
			@Override
			public void run() {
				for(int i=0; i< 5; i++) {
					t.setTotalTax(c);
				}
			}			
		});	
		
		tOne.start();
		tTwo.start();
	}
public class Tax {

	private double totalTax;
	
	public synchronized void setTotalTax(Cart c) {
		totalTax = c.getTotalPrice()*30/100;
	}
	
	public synchronized double getTotalTax() {
		return totalTax;
	}
}
public class Cart {
	private double totalPrice;

	public synchronized double getTotalPrice() {
		return totalPrice;
	}
	public synchronized void addToTotalPrice(double itemPrice, Tax t) { 

		if(t.getTotalTax() > 200) {
			itemPrice = itemPrice - t.getTotalTax()*5;
		}
		totalPrice = totalPrice + itemPrice;
		
		//add this to simulate a little long running methods
		try {
			Thread.sleep(15);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}	
}

Starvation

Another issue caused by synchronization is starvation which occurs when a thread acquire a lock and holds it for long time blocking other threads waiting for the lock of the same object. You can use ReentrantLock to solve the starvation issue.

	public static void main(String[] args) {
		
		Cart c = new Cart();
		
		Thread thradOne = new Thread(new Runnable() {
			@Override
			public void run() {
				synchronized(c) {
					c.addToTotalPrice(222);
				}
			}			
		});
		thradOne.start();
		
		Thread threadTwo = new Thread(new Runnable() {
			@Override
			public void run() {
				synchronized(c) {
					c.addToTotalPrice(333);
				}
			}			
		});
		threadTwo.start();

	}
public class Cart {
	private double totalPrice;

	public double getTotalPrice() {
		return totalPrice;
	}
	public void addToTotalPrice(double itemPrice) { 

		totalPrice = totalPrice + itemPrice;
		
		//add this to simulate a little long running methods
		try {
			Thread.sleep(4500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}	
}

To solve starvation issue, instead of using intrinsic lock, we can use ReentrantLock. With ReentrantLock, second thread can try to get a lock for reasonable amount of time and after that it can log message about its inability to get the lock and continue. The following example uses ReentrantLock, second thread tries to get lock for 600 milliseconds and logs message if it can’t acquire lock in the specified time and continues.

public static void main(String[] args) {
	final Lock lock = new ReentrantLock();
	
	Cart c = new Cart();
	
	Thread thradOne = new Thread(new Runnable() {
		@Override
		public void run() {
			lock.lock();

			try{
				c.addToTotalPrice(222);
				System.out.println("thread one ");
			}finally {
				lock.unlock();
			}
		}			
	});
	thradOne.start();
	
	Thread threadTwo = new Thread(new Runnable() {
		boolean gotLock;
		@Override
		public void run() {
			try {
				if(lock.tryLock(600, TimeUnit.MILLISECONDS)) {
					gotLock = true;
					c.addToTotalPrice(333);
					System.out.println("thread two");
				}else {
					System.out.println("could't add price to cart "
								+Thread.currentThread().getName());
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}finally {
				if(gotLock) {
					lock.unlock();
				}
			}
		}			
	});
	threadTwo.start();
}

Livelock

An issue caused by dependency of a thread on the action of another thread which in turn depends on the action of first thread is called livelock. Livelock doesn’t block the threads, but threads are busy in repeatedly checks for a condition which will never become true. Livelock can be avoided by proper design and coding of your program. Following example runs forever due to livelock issue.

	public static void main(String[] args) {	
		
		Item itemOne = new Item();
		Item itemTwo = new Item();
		
		Thread tOne = new Thread(new Runnable() {
			@Override
			public void run() {
				while(!itemOne.isSelected()) {
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				itemTwo.setSelected(true);
			}			
		});		
		
		Thread tTwo = new Thread(new Runnable() {
			@Override
			public void run() {
				while(!itemTwo.isSelected()) {
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				itemOne.setSelected(true);
			}			
		});	
		
		tOne.start();
		tTwo.start();
	}
public class Item {
	boolean selected = false;

	public boolean isSelected() {
		return selected;
	}

	public void setSelected(boolean selected) {
		this.selected = selected;
	}

}

Inter Thread Communication

When threads share an object, communication between the threads can help in improving the performance of applications. When there is a guarded block, meaning certain statements must be executed but only on fulfilling a condition, instead of repeatedly checking for the condition, the thread executing the code can be made to release the lock of the object and wait for other threads to notify about updates to the object. On notification, the thread can continue checking for the condition and execute the statements.

This inter thread communication can be implemented using notify(), notifyAll() and wait() methods of the Object class. These methods are interruptible meaning they throw InterruptedException exception when the thread is interrupted by calling interrupt() method.

The wait() method makes the current thread release the lock of the object on which it is called and wait for the notifications from other threads. Other threads waiting for the lock of the object will continue with the execution and then calls notify() and notifyAll() once it is done with execution. Single thread or one of the threads waiting on the object’s monitor will continue with execution after notify or notifyAll calls from different thread.

If notify, wait, notifyAll methods are not called within the synchronized method or block, IllegalMonitorStateException exception will be thrown.

Following example shows how to impelment inter thread communication. Instance of LatestCoupon is the shared object between two threads. LatestCoupon class contains two synchronized methods with wait and notifyAll calls. Two threads run LatestCouponProvider and LatestCouponDisplayer for providing latest coupon and displaying it.

public class LatestCoupon {
	
	private String coupon;
	private boolean latest;
	private int count = 1;
	
	public synchronized String getCoupon() {
		//wait if not latest coupon
		while(!latest) {
			try {
				wait();
			} catch (InterruptedException e) {}
		}
		
		//set latest coupon back to false 
		latest = false;
		//notify threads waiting
		notifyAll();
		
		return coupon;
	}
	public synchronized void setCoupon(String coupon) {
		//wait if latest coupon, not consumed one
		while(latest) {
			try {
				wait();
			} catch (InterruptedException e) {}
		}
		//set latest coupon to true
		latest = true;
		this.coupon = coupon;
		//notify threads
		notifyAll();
	}
	public int getCount() {
		return count;
	}
	public void setCount(int count) {
		this.count = count;
	}	
}
public class LatestCouponProvider implements Runnable {
	private LatestCoupon lc;

	public LatestCouponProvider(LatestCoupon lcoupon) {
		lc = lcoupon;
	}
	
	@Override
	public void run() {
		processCoupons();
	}
	
	private void processCoupons(){
		List<String> coupons = new ArrayList<String>();
		coupons.add("flat 20% off on mobiles");
		coupons.add("upto 50% off on tablets");
		coupons.add("get 30% off on fashion");
		coupons.add("upto 10% off on laptops");
		
		lc.setCount(coupons.size());
		
		for(String cpn :  coupons) {
			publishLatestCoupons(cpn);
		}
	}
	
	private void publishLatestCoupons(String cpn) {
		lc.setCoupon(cpn);
        try {
            Thread.sleep(400);
        } catch (InterruptedException e) {}
	}
}
public class LatestCouponDisplayer implements Runnable{
	
	private LatestCoupon lc;
	
	public LatestCouponDisplayer(LatestCoupon lcoupon) {
		lc = lcoupon;
	}
	
	@Override
	public void run() {
		displayCoupon();
	}
	private void displayCoupon() {
		while(lc.getCount() > 0) {
			String lcoupon = lc.getCoupon();
			lc.setCount(lc.getCount() - 1);
			System.out.println(lcoupon);
			System.out.println(lc.getCount());
			try {
				Thread.sleep(400);
			} catch (InterruptedException e) {}
		}
	}
}
	LatestCoupon lc = new LatestCoupon();		
	Thread threadOne = new Thread(new LatestCouponProvider(lc));
	    Thread threadTwo = new Thread(new LatestCouponDisplayer(lc));
	    threadOne.start();
	    threadTwo.start();