SoFunction
Updated on 2025-04-13

Detailed explanation of several ways of communication between Java threads

1. Shared variables and synchronization mechanism

Multiple threads can communicate through shared objects' variables, but to avoid data inconsistencies, a synchronization mechanism must be used to control access to shared variables.

  • usesynchronizedKeywords: synchronizedMake sure that only one thread can execute synchronous code blocks at the same time. It can synchronize methods or code blocks to protect shared data.

    Example:

class Counter {
    private int count = 0;
 
    public synchronized void increment() {
        count++;
    }
 
    public synchronized int getCount() {
        return count;
    }
}
 
public class SyncExample {
    public static void main(String[] args) {
        Counter counter = new Counter();
 
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                ();
            }
        });
 
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                ();
            }
        });
 
        ();
        ();
 
        try {
            ();
            ();
        } catch (InterruptedException e) {
            ();
        }
 
        ("Final count: " + ());
    }
}
  • Use scenarios: Used to protect shared resources and prevent multiple threads from reading and writing at the same time causing data inconsistency.

  • usevolatileKeywords: volatileEnsure that one thread's modification of variables is immediately visible to other threads. It is suitable for lightweight variable synchronization and is usually used for flag bit control.

    Example:

class Flag {
    private volatile boolean running = true;
 
    public void stop() {
        running = false;
    }
 
    public boolean isRunning() {
        return running;
    }
}
 
public class VolatileExample {
    public static void main(String[] args) {
        Flag flag = new Flag();
 
        Thread t1 = new Thread(() -> {
            while (()) {
                ("Thread is running");
            }
            ("Thread stopped");
        });
 
        ();
 
        try {
            (2000);
        } catch (InterruptedException e) {
            ();
        }
 
        ();
    }
}
  • Use scenarios: Used to control the exit of threads, switch operations and other lightweight scenarios.

2. wait(), notify() and notifyAll()

ObjectThese three methods of the class are used to implement collaboration between threads within a synchronization block. Threads can passwait()Enter the waiting state until another thread callsnotify()ornotifyAll()Awaken them.

  • wait(): The current thread enters a waiting state and releases the lock.
  • notify(): Wake up a thread waiting for the same lock.
  • notifyAll(): Wake up all threads waiting for the same lock.

Example: Producer-Consumer Model

class SharedResource {
    private int value;
    private boolean hasValue = false;
 
    public synchronized void produce(int newValue) throws InterruptedException {
        while (hasValue) {
            wait(); // Wait for consumer consumption        }
        value = newValue;
        hasValue = true;
        ("Produced: " + value);
        notify(); // Awaken the consumer    }
 
    public synchronized void consume() throws InterruptedException {
        while (!hasValue) {
            wait(); // Wait for producers to produce        }
        ("Consumed: " + value);
        hasValue = false;
        notify(); // Wake up the producer    }
}
 
public class ProducerConsumerExample {
    public static void main(String[] args) {
        SharedResource resource = new SharedResource();
 
        Thread producer = new Thread(() -&gt; {
            try {
                for (int i = 0; i &lt; 5; i++) {
                    (i);
                    (100);
                }
            } catch (InterruptedException e) {
                ();
            }
        });
 
        Thread consumer = new Thread(() -&gt; {
            try {
                for (int i = 0; i &lt; 5; i++) {
                    ();
                    (200);
                }
            } catch (InterruptedException e) {
                ();
            }
        });
 
        ();
        ();
    }
}

Use scenarios: Applicable to coordination work between threads, such as the producer-consumer model, where one thread is responsible for producing resources and the other thread is responsible for consuming resources.

3. Lock and Condition interfaces

compared tosynchronizedLockProvides a more flexible synchronization mechanism, andConditionCan be replacedwait()notify()andnotifyAll(), and supports multiple waiting conditions.

  • ReentrantLock: Commonly used for explicit lock control, it can provide a fair lock mechanism (scheduled in the order in which the locks are acquired).
  • Condition: Similar toObjectofwait()notify(), multipleConditionTo perform complex thread coordination.

Example:

import ;
import ;
import ;
 
class BoundedBuffer {
    private final int[] buffer;
    private int count, in, out;
    private final Lock lock = new ReentrantLock();
    private final Condition notFull = ();
    private final Condition notEmpty = ();
 
    public BoundedBuffer(int size) {
        buffer = new int[size];
    }
 
    public void put(int value) throws InterruptedException {
        ();
        try {
            while (count == ) {
                (); // Wait for the buffer not full            }
            buffer[in] = value;
            in = (in + 1) % ;
            count++;
            (); // Wake up the consumer thread        } finally {
            ();
        }
    }
 
    public int take() throws InterruptedException {
        ();
        try {
            while (count == 0) {
                (); // Wait for the buffer to be non-empty            }
            int value = buffer[out];
            out = (out + 1) % ;
            count--;
            (); // Wake up the production thread            return value;
        } finally {
            ();
        }
    }
}
 
public class LockConditionExample {
    public static void main(String[] args) {
        BoundedBuffer buffer = new BoundedBuffer(5);
 
        Thread producer = new Thread(() -&gt; {
            try {
                for (int i = 0; i &lt; 10; i++) {
                    (i);
                    ("Produced: " + i);
                }
            } catch (InterruptedException e) {
                ();
            }
        });
 
        Thread consumer = new Thread(() -&gt; {
            try {
                for (int i = 0; i &lt; 10; i++) {
                    int value = ();
                    ("Consumed: " + value);
                }
            } catch (InterruptedException e) {
                ();
            }
        });
 
        ();
        ();
    }
}

Use scenarios: Suitable for more complex conditional waiting scenarios that require explicit locking, such as multi-conditional synchronization, multi-producer-consumer model.

4. Package concurrency tools

Java providesA series of advanced concurrency tool classes under the package to simplify inter-thread communication.

  • BlockingQueue: Thread-safe queues, often used in the producer-consumer mode.
  • CountDownLatch: Allows one or more threads to wait for other threads to complete certain operations.
  • CyclicBarrier: Multiple threads wait for each other at a point until all threads reach that point.
  • Semaphore: Used to control access permissions to resources.
  • Exchanger: Used to exchange data between two threads.

This is the end of this article about several detailed explanations of Java thread communication. For more related communication content between Java threads, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!