Thread Communication in Java: volatile, wait/notify, CountDownLatch, ReentrantLock+Condition, and LockSupport
This article explains five Java thread‑communication techniques—volatile variables, Object.wait()/notify(), CountDownLatch, ReentrantLock with Condition, and LockSupport—providing code examples and detailed explanations of how each method works and its synchronization behavior, including sample programs that add elements to a list, demonstrate notification timing, and show how locks are acquired and released.
In this tutorial a senior architect presents five common Java thread‑communication mechanisms.
Using the volatile keyword
Using Object.wait() / Object.notify()
Using JUC CountDownLatch
Using ReentrantLock with Condition
Using LockSupport
1. Using volatile
Based on the volatile keyword, multiple threads share a variable; when the variable changes, other threads can perceive the change and execute related business logic. This is the simplest shared‑memory approach.
public class TestSync {
// Define a shared volatile flag
static volatile boolean notice = false;
public static void main(String[] args) {
List
list = new ArrayList<>();
// Thread A
Thread threadA = new Thread(() -> {
for (int i = 1; i <= 10; i++) {
list.add("abc");
System.out.println("线程A添加元素,此时list的size为:" + list.size());
try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }
if (list.size() == 5) notice = true;
}
});
// Thread B
Thread threadB = new Thread(() -> {
while (true) {
if (notice) {
System.out.println("线程B收到通知,开始执行自己的业务...");
break;
}
}
});
// Start B first
threadB.start();
try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
// Then start A
threadA.start();
}
}2. Using Object.wait()/notify()
The Object class provides the fundamental thread‑communication methods wait() , notify() , and notifyAll() . They must be used inside a synchronized block; wait() releases the lock, while notify() does not release it immediately.
public class TestSync {
public static void main(String[] args) {
Object lock = new Object();
List
list = new ArrayList<>();
// Thread A
Thread threadA = new Thread(() -> {
synchronized (lock) {
for (int i = 1; i <= 10; i++) {
list.add("abc");
System.out.println("线程A添加元素,此时list的size为:" + list.size());
try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }
if (list.size() == 5) lock.notify(); // wake up B
}
}
});
// Thread B
Thread threadB = new Thread(() -> {
while (true) {
synchronized (lock) {
if (list.size() != 5) {
try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); }
}
System.out.println("线程B收到通知,开始执行自己的业务...");
}
break;
}
});
threadB.start();
try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
threadA.start();
}
}3. Using JUC CountDownLatch
Since JDK 1.5, the java.util.concurrent package offers utilities like CountDownLatch , which internally uses an AQS state to coordinate threads.
public class TestSync {
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(1);
List
list = new ArrayList<>();
// Thread A
Thread threadA = new Thread(() -> {
for (int i = 1; i <= 10; i++) {
list.add("abc");
System.out.println("线程A添加元素,此时list的size为:" + list.size());
try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }
if (list.size() == 5) countDownLatch.countDown();
}
});
// Thread B
Thread threadB = new Thread(() -> {
while (true) {
if (list.size() != 5) {
try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); }
}
System.out.println("线程B收到通知,开始执行自己的业务...");
break;
}
});
threadB.start();
try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
threadA.start();
}
}4. Using ReentrantLock with Condition
ReentrantLock combined with a Condition offers explicit lock control and separate wait‑sets, but the waking thread still must acquire the lock before proceeding.
public class TestSync {
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
List
list = new ArrayList<>();
// Thread A
Thread threadA = new Thread(() -> {
lock.lock();
for (int i = 1; i <= 10; i++) {
list.add("abc");
System.out.println("线程A添加元素,此时list的size为:" + list.size());
try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }
if (list.size() == 5) condition.signal();
}
lock.unlock();
});
// Thread B
Thread threadB = new Thread(() -> {
lock.lock();
if (list.size() != 5) {
try { condition.await(); } catch (InterruptedException e) { e.printStackTrace(); }
}
System.out.println("线程B收到通知,开始执行自己的业务...");
lock.unlock();
});
threadB.start();
try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
threadA.start();
}
}5. Using LockSupport
LockSupport provides flexible park/unpark operations that do not depend on lock ownership, allowing a thread to block until another thread explicitly unparks it.
public class TestSync {
public static void main(String[] args) {
List
list = new ArrayList<>();
final Thread threadB = new Thread(() -> {
if (list.size() != 5) {
LockSupport.park();
}
System.out.println("线程B收到通知,开始执行自己的业务...");
});
Thread threadA = new Thread(() -> {
for (int i = 1; i <= 10; i++) {
list.add("abc");
System.out.println("线程A添加元素,此时list的size为:" + list.size());
try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }
if (list.size() == 5) LockSupport.unpark(threadB);
}
});
threadA.start();
threadB.start();
}
}Each method has its own characteristics regarding lock release, notification timing, and code complexity, allowing developers to choose the most suitable approach for their concurrency scenarios.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.