Java - Multi Threading

<<Previous

Learn C Programming>>




Multi Threading and Concurrency

Multi Threading is a concept by which the activities that can be executed in parallel will be executed in different lines of execution called the thread.

In a single core processor machine, the CPU time will be shared by the threads running in parallel. This is used to reduce the overall idle time like waiting for user input, waiting for network data or waiting for something else. Also, it also helps which activities should be given higher priority by using Thread priorities.

In a multiple core processor machine, concurrency support in Java helps to run different threads in different processor cores and thus utilizing the speed of all the cores.

Java Threads

Thread is a line of execution. A Thread can be started in Java using the class Thread

Sometimes, a thread can be created by

  • extending the class Thread
  • implement the interface Runnable and passing Runnable implementation reference to the Thread constructor

Example - Extending class Thread

	public class ThreadExample extends Thread{
		String threadName;

		public ThreadExample(String name){
			this.threadName=name;
		}
		public void run(){
			System.out.println("Inside thread: " + threadName);
		}

		public static void main(String a[]){
			ThreadExample thread1= new ThreadExample("Thread1");
			ThreadExample thread2= new ThreadExample("Thread2");
			ThreadExample thread3= new ThreadExample("Thread3");
			ThreadExample thread4= new ThreadExample("Thread4");
			thread1.start();
			thread2.start();
			thread3.start();
			thread4.start();
		}

}

Please note that the output displayed below varies from time to time based on when the individual threads start

Output - Extending class Thread

Inside Runnable thread: Thread3
Inside Runnable thread: Thread4
Inside Runnable thread: Thread2
Inside Runnable thread: Thread1

Example - Thread implementing interface Runnable


public class ThreadUsingRunnableExample implements Runnable{
	String threadName;

	public ThreadUsingRunnableExample(String name){
		this.threadName=name;
	}
	public void run(){
		System.out.println("Inside Runnable thread: " + threadName);
	}

	public static void main(String a[]){

		Thread thread1 = new Thread(new ThreadUsingRunnableExample("Thread1"));
		Thread thread2 = new Thread(new ThreadUsingRunnableExample("Thread2"));
		Thread thread3 = new Thread(new ThreadUsingRunnableExample("Thread3"));
		Thread thread4 = new Thread(new ThreadUsingRunnableExample("Thread4"));

		thread1.start();
		thread2.start();
		thread3.start();
		thread4.start();

	}

}

Output - Thread implementing interface Runnable

Inside Runnable thread: Thread3
Inside Runnable thread: Thread4
Inside Runnable thread: Thread2
Inside Runnable thread: Thread1

Thread - sleep() method

sleep() method is a static method and can be called on Thread class directly to make the current sleep for a specified number of millseconds. If a Thread sleeps, other threads get the time to execute

Example - using Thread sleep method

public class ThreadSleepExample extends Thread{
	String threadName;

	public ThreadSleepExample(String name){
		this.threadName=name;

	}
	public void run(){
		if(threadName.equals("Thread1")){
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println("Inside thread: " + threadName);
	}

	public static void main(String a[]) {
		ThreadSleepExample thread1= new ThreadSleepExample("Thread1");
		ThreadSleepExample thread2= new ThreadSleepExample("Thread2");
		ThreadSleepExample thread3= new ThreadSleepExample("Thread3");
		ThreadSleepExample thread4= new ThreadSleepExample("Thread4");

		thread1.start();
		thread2.start();
		thread3.start();
		thread4.start();
	}

}

Thread - join() method

When join() is invoked on a particular thread, the current thread waits for the invoked thread to terminate. Once the invoked thread dies, the current thread continues its execution

Consider the below example when multiple threads execute and join() method is NOT used

Example - Threads without join

public class ThreadWithoutJoin implements Runnable{
	String threadName;
	int sum=0;
	public ThreadWithoutJoin(String name){
		this.threadName=name;

	}
	public void run(){
			try{
			Thread.sleep(1000);
			}
			catch(InterruptedException ie){
				ie.printStackTrace();
			}
			for(int i=0;i<1000;i++){
				sum=sum+i;
			}
	}

	public void printSum(){
		System.out.println(threadName+ ":"+sum);

	}

	public static void main(String a[]) {
		ThreadWithoutJoin te1= new ThreadWithoutJoin("Thread1");
		ThreadWithoutJoin te2= new ThreadWithoutJoin("Thread2");
		ThreadWithoutJoin te3= new ThreadWithoutJoin("Thread3");
		ThreadWithoutJoin te4= new ThreadWithoutJoin("Thread4");
		Thread thread1=new Thread(te1);
		Thread thread2=new Thread(te2);
		Thread thread3=new Thread(te3);
		Thread thread4=new Thread(te4);
		thread1.start();
		thread2.start();
		thread3.start();
		thread4.start();

		te1.printSum();
		te2.printSum();
		te3.printSum();
		te4.printSum();

	}

}

Output - ThreadWithoutJoin

Thread1:0
Thread2:0
Thread3:0
Thread4:0

In the above example, main thread terminates before the 4 invoked threads thread1, thread2, thread3 and thread4 complete calculating the sum and hence the result expected is not printed. If Thread join() method is called on each of the instance, the main thread waits until each of invoked instance completes the calculation and terminates.

Example - MultiThreading using join

public class ThreadJoinExample implements Runnable{
	String threadName;
	int sum=0;
	public ThreadJoinExample(String name){
		this.threadName=name;

	}
	public void run(){
		try{
		Thread.sleep(1000);
		}
		catch(InterruptedException ie){
			ie.printStackTrace();
		}
		for(int i=0;i<1000;i++){
			sum=sum+i;
		}
	}


	public void printSum(){
		System.out.println(threadName+ ":"+sum);

	}

	public static void main(String a[]) {
		ThreadJoinExample te1= new ThreadJoinExample("Thread1");
		ThreadJoinExample te2= new ThreadJoinExample("Thread2");
		ThreadJoinExample te3= new ThreadJoinExample("Thread3");
		ThreadJoinExample te4= new ThreadJoinExample("Thread4");
		Thread thread1=new Thread(te1);
		Thread thread2=new Thread(te2);
		Thread thread3=new Thread(te3);
		Thread thread4=new Thread(te4);
		thread1.start();
		thread2.start();
		thread3.start();
		thread4.start();

		try {
			thread1.join();
			thread2.join();
			thread3.join();
			thread4.join();

		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		te1.printSum();
		te2.printSum();
		te3.printSum();
		te4.printSum();
	}

}

Output - MultiThreading using join

Thread1:499500
Thread2:499500
Thread3:499500
Thread4:499500

Thread - wait() and notify() methods

Whenever we execute a main method, we will have Main Thread running. In our example, we execute a new thread invoked from the main method. New Thread is doing the calculations. The main thread needs to print the result of the output of the new thread.

Example - Thread without using wait() and notify() methods

		public class ThreadWithoutWaitAndNotifyExample extends Thread{
			String threadName;
			int sum;
			public ThreadWithoutWaitAndNotifyExample(String name){
				this.threadName=name;
			}
			public void run(){
				System.out.println("Inside thread: " + threadName);
				sum=0;
				for(int i=0; i<1000;i++){
						sum=sum+i;
				}
			}

			//Main Thread
			public static void main(String a[]){
				ThreadWithoutWaitAndNotifyExample thread1
							= new ThreadWithoutWaitAndNotifyExample("Thread1");
				thread1.start();
				System.out.println("sum:"+thread1.sum);
			}
		}
	

Output - Thread without using wait() and notify() method

	sum:0
	Inside thread: Thread1
	

In the above code, Main thread prints the results before the other thread (thread1) calculates the sum of numbers 1 to 1000. This is because the main thread (current thread) did not wait for the other thread to complete. In order to make the main thread (current thread) wait for thread1 to complete, we need to call thread1.wait() from within the main method().

Example - MultiThreading with wait() and notify()

	public class ThreadWaitAndNotifyExample extends Thread{
		String threadName;
		int sum;
		public ThreadWaitAndNotifyExample(String name){
			this.threadName=name;
		}
		public void run(){
			System.out.println("Inside thread: " + threadName);
			sum=0;
			synchronized(this){
				for(int i=0; i<1000;i++){
					sum=sum+i;
				}
				notify();
			}

		}

		public static void main(String a[]){
			ThreadWaitAndNotifyExample thread1= new ThreadWaitAndNotifyExample("Thread1");
			thread1.start();
				try {
					synchronized(thread1){
						thread1.wait();
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			System.out.println("sum:"+thread1.sum);
		}

	}

Output - MultiThreading with wait() and notify()

Inside thread: Thread1
sum:499500

Thread - yield() method

Example - Thread using yield() method

	public class ThreadYieldExample extends Thread{
		String threadName;
		int number;
		public ThreadYieldExample(String name, int number){
			this.threadName=name;
			this.number=number;
		}
		public void run(){
			if(threadName.equals("Thread1")){
				System.out.println("Thread1 yielding..");
				yield();
			}
				System.out.println(threadName+" "+ Math.pow(number, 100));

		}

		public static void main(String a[]){
			ThreadYieldExample thread1= new ThreadYieldExample("Thread1",2);
			ThreadYieldExample thread2= new ThreadYieldExample("Thread2",3);
			ThreadYieldExample thread3= new ThreadYieldExample("Thread3",4);
			ThreadYieldExample thread4= new ThreadYieldExample("Thread4",5);

			thread1.start();
			thread2.start();
			thread3.start();
			thread4.start();
		}
	}

Output - yield() method

Thread1 yielding..
Thread4 7.888609052210118E69
Thread3 1.6069380442589903E60
Thread2 5.153775207320113E47
Thread1 1.2676506002282294E30

<<Previous

Learn C Programming>>