Thread Communication
In concurrent programming, it is often necessary for threads to communicate with each other to synchronize their actions and share data. Thread communication enables threads to coordinate their execution and avoid race conditions.
Why do we need thread communication?
Thread communication is essential when multiple threads are executing concurrently and need to cooperate to accomplish a task. Without communication, threads may interfere with each other, leading to inconsistent results and race conditions. By enabling threads to exchange information, synchronize their actions, and properly share data, we can ensure thread safety and avoid conflicts.
Techniques for Thread Communication
Java provides several techniques for thread communication:
wait()
andnotify()
: Thewait()
andnotify()
methods are used to block and wake up threads respectively. Threads can call thewait()
method to suspend their execution and wait until another thread notifies them using thenotify()
ornotifyAll()
method.synchronized
keyword: Thesynchronized
keyword is not only used for mutual exclusion but also for thread communication. When a thread owns the monitor of an object using thesynchronized
keyword, it can use thewait()
andnotify()
methods to communicate with other threads. This ensures that threads can safely wait and notify each other while accessing shared resources.
Let's take a look at an example that demonstrates thread communication using the wait()
and notify()
methods:
1// Create a shared Queue
2class Queue {
3 private int value;
4
5 // Method to add a value to the Queue
6 public synchronized void put(int value) {
7 // Wait until the queue is empty
8 while (this.value != 0) {
9 try {
10 wait();
11 } catch (InterruptedException e) {
12 e.printStackTrace();
13 }
14 }
15
16 // Add the value to the queue
17 this.value = value;
18
19 // Notify other threads that the queue is not empty
20 notify();
21 }
22
23 // Method to remove a value from the Queue
24 public synchronized int get() {
25 // Wait until the queue is not empty
26 while (this.value == 0) {
27 try {
28 wait();
29 } catch (InterruptedException e) {
30 e.printStackTrace();
31 }
32 }
33
34 // Get the value from the queue
35 int temp = this.value;
36
37 // Clear the queue
38 this.value = 0;
39
40 // Notify other threads that the queue is empty
41 notify();
42
43 // Return the value
44 return temp;
45 }
46}
47
48// Create a producer thread
49class Producer implements Runnable {
50 private Queue queue;
51
52 public Producer(Queue queue) {
53 this.queue = queue;
54 }
55
56 public void run() {
57 for (int i = 1; i <= 10; i++) {
58 queue.put(i);
59 System.out.println("Producer put: " + i);
60 }
61 }
62}
63
64// Create a consumer thread
65class Consumer implements Runnable {
66 private Queue queue;
67
68 public Consumer(Queue queue) {
69 this.queue = queue;
70 }
71
72 public void run() {
73 for (int i = 1; i <= 10; i++) {
74 int value = queue.get();
75 System.out.println("Consumer got: " + value);
76 }
77 }
78}
79
80// Usage example
81Queue queue = new Queue();
82
83// Create producer and consumer threads
84Thread producerThread = new Thread(new Producer(queue));
85Thread consumerThread = new Thread(new Consumer(queue));
86
87// Start the threads
88producerThread.start();
89consumerThread.start();