Mark As Completed Discussion

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() and notify(): The wait() and notify() methods are used to block and wake up threads respectively. Threads can call the wait() method to suspend their execution and wait until another thread notifies them using the notify() or notifyAll() method.

  • synchronized keyword: The synchronized keyword is not only used for mutual exclusion but also for thread communication. When a thread owns the monitor of an object using the synchronized keyword, it can use the wait() and notify() 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:

TEXT/X-JAVA
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();