Complete guide to Java Multithreading/Synchronization

Content to be covered:​

  1. Java Multi-threading
  2. Synchronized Method & Block in Java
  3. wait() and notify() methods in Java
  4. Classical Producer & Consumer Problem in Java
  5. Thread Life Cycle
  6. Multi-tasking in Java

What is Java Multi-threading?

public class MultiThreadingInJava {

	public static void main(String[] args) throws InterruptedException {

		
                C1 obj1 = new C1();
		obj1.show1();
		
		System.out.println("\n");
		C2 obj2 = new C2();
		obj2.show2();

}
class C1 {
	void show1() {

		Scanner obj = new Scanner(System.in);
		System.out.println("Enter the value of a: ");
		int a = obj.nextInt();
		
		System.out.println(a);
		System.out.println("Done with show1()!");
		obj.close();
	
	}
}

class C2 {
	void show2() {
		for (int i = 0; i < 10; i++) {
			System.out.println(i + "- Hey_2!");
		}
	}
}
public class MultiThreadingInJava {

	public static void main(String[] args) throws InterruptedException {

		
                Thread t1 = new Thread(new T1(), "T1 Name");
		Thread t2 = new Thread(new T2(), "T2 Name");
                
                t1.start();
		t2.start();

                
                System.out.println(Thread.currentThread().getName());
		System.out.println("Done with work!");

}
class T1 extends Thread {
	
	void display() {
		System.out.println("Hello!");
	}

	@Override
	public void run() {

		Scanner obj = new Scanner(System.in);
		System.out.println("Enter the value of a as integer: ");
		int a = obj.nextInt();
		
		System.out.println(a);
		System.out.println("Done with T1!");
		System.out.println(Thread.currentThread().getName());

		obj.close();

	}
}

class T2 implements Runnable {

	@Override
	public void run() {
		System.out.println("Entered in Thread T2: ");
		for (int i = 0; i < 1000; i++) {
			System.out.println(i + "- Hey_2!");
//			System.out.println(Thread.currentThread().getName());
		}
		System.out.println(Thread.currentThread().getName());
		System.out.println("Done with thread T2!");
	}
}

What are Synchronized Method & Block in Java?

package Unit_03_Concepts;

public class SampleClass {

	public static void main(String[] args) throws InterruptedException {
		WebCountData obj = new WebCountData();
		
		Thread t1 = new Thread(new Runnable() {
			
			@Override
			public void run() {
				
				for(int i = 0; i<1000; i++) {
					obj.WebCount2();
				}
				
			}
		});
		
		Thread t2 = new Thread(new Runnable() {
						
			@Override
			public void run() {
				
				for(int i = 0; i<1000; i++) {
					obj.WebCount2();
				}
				
			}
		});
	
		t1.start();
		t2.start();
		
		t1.join();
		t2.join();
		
		System.out.println(WebCountData.count);
		System.out.println(Thread.currentThread().getName());
	
	}
}

class WebCountData{
	static int count = 0;
	synchronized public void WebCount1() {
		System.out.println("Inaside WebCount1 Method");
		System.out.println("Inaside WebCount1 Method");
		System.out.println("Inaside WebCount1 Method");
		System.out.println("Inaside WebCount1 Method");
		count++;
	}
	
	public void WebCount2() {
		System.out.println("Inaside WebCount2 Method");
		System.out.println("Inaside WebCount2 Method");
		System.out.println("Inaside WebCount2 Method");
		System.out.println("Inaside WebCount2 Method");
		
		synchronized(this) {			
			count++;
		}
		
	}
}

What are wait() and notify() methods in Java?

public class SampleClass {

	public static void main(String[] args) {

		SharedResource c = new SharedResource();
	
		
		new Thread(new Runnable() {
				
			@Override
			public void run() {
				c.withdraw(15000);
			}
		}).start();
		
		new Thread() {
			public void run() {
				c.withdraw(15000);
			}
		}.start();

		new Thread() {
			public void run() {
				c.withdraw(15000);
			}
		}.start();

		new Thread() {
			public void run() {
				c.withdraw(15000);
			}
		}.start();

		new Thread() {
			public void run() {
				c.withdraw(15000);
			}
		}.start();

		new Thread() {
			public void run() {
				c.deposit(10000);
			}
		}.start();
	}

}

class SharedResource {
	int amount = 10000;

	synchronized void withdraw(int amount) {
		System.out.println("going to withdraw..." + amount);

		if (this.amount < amount) {
			System.out.println("Less balance; waiting for deposit...");
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		int temp = this.amount - amount;

//		this.amount -= amount;

		if (temp < 0) {
			System.out.println("Negative Balance");
			try {
				wait();
			} catch (Exception e) {
			}
		}
		
		this.amount = temp;

		System.out.println("Now total amount is: " + this.amount);
		System.out.println("withdraw completed...");

	}

	synchronized void deposit(int amount) {
		System.out.println("going to deposit: " + amount);
		this.amount += amount;
		System.out.println("deposit completed... ");
		System.out.println("Now total amount is: " + this.amount);
		notifyAll();
	}
}

What is Producer & Consumer Problem in Java?

public class SampleClass {

	public static void main(String[] args) {

		Queue<Integer> buffer = new LinkedList<>();
		int maxSize = 10;
		
		Thread producer = new Producer(buffer, maxSize, "PRODUCER");
		Thread consumer = new Consumer(buffer, maxSize, "CONSUMER");

		producer.start();
		consumer.start();

	}

}

class Producer extends Thread {
	private Queue<Integer> queue;
	private int maxSize;

	public Producer(Queue<Integer> queue, int maxSize, String name) {
		super(name);
		this.queue = queue;
		this.maxSize = maxSize;
	}

	@Override
	public synchronized void run() {
		while (true) {
			synchronized (queue) {
				while (queue.size() == maxSize) {
					try {
						System.out.println("Queue is full, " + "Producer thread waiting for "
								+ "consumer to take something from queue");
						queue.wait();
					} catch (Exception ex) {
						ex.printStackTrace();
					}
				}
				Random random = new Random();
				int i = random.nextInt();
				System.out.println("Producing value : " + i);
				queue.add(i);
				queue.notify();
			}
		}
		
	}
}

class Consumer extends Thread {
	private Queue<Integer> queue;
	private int maxSize;

	public Consumer(Queue<Integer> queue, int maxSize, String name) {
		super(name);
		this.queue = queue;
		this.maxSize = maxSize;
	}

	@Override
	public  void run() {
		while (true) {
			synchronized (queue) {
				while (queue.isEmpty()) {
					System.out.println("Queue is empty," + "Consumer thread is waiting"
							+ " for producer thread to put something in queue");
					try {
						queue.wait();
					} catch (Exception ex) {
						ex.printStackTrace();
					}
				}
				System.out.println("Consuming value : " + queue.remove());
				queue.notify();
			}
		}
	}
}

What are the Thread Life Cycle & Multi-tasking in Java?

🔴 LIVE: Java Multithreading Deep Dive | Complete Guide + Q&A Session


Chapters (Clickable):

Assignment/Questions for Practice:

Thanks and Regards,