使用Condition实现线程间的精准通信
在Java并发编程中,除了synchronized配合wait()和notify()进行线程协作外,Lock接口提供了更灵活的同步机制。通过ReentrantLock结合Condition,可以实现对线程等待与唤醒的精细化控制。
以一个基础的生产者-消费者模型为例,使用synchronized时,线程通过wait()进入等待状态,由notifyAll()唤醒其他线程。但在复杂场景下,这种"全唤醒"方式效率较低且无法指定唤醒目标。
改用Lock后,await()和signal()替代了原有的wait()和notify(),核心逻辑保持一致:
class SharedResource {
private int value = 0;
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
public void increment() {
lock.lock();
try {
while (value != 0) {
condition.await();
}
Thread.sleep(100);
value++;
System.out.println(Thread.currentThread().getName() + " -> " + value);
condition.signalAll();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
}
public void decrement() {
lock.lock();
try {
while (value == 0) {
condition.await();
}
Thread.sleep(100);
value--;
System.out.println(Thread.currentThread().getName() + " -> " + value);
condition.signalAll();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
}
}
然而,Condition真正的优势在于支持多个独立的等待队列。通过创建多个Condition实例,可实现线程间有序执行。例如,要求三个线程按A→B→C顺序循环打印:
class OrderedPrinter {
private int sequence = 1;
private final Lock lock = new ReentrantLock();
private final Condition condA = lock.newCondition();
private final Condition condB = lock.newCondition();
private final Condition condC = lock.newCondition();
public void printA() {
lock.lock();
try {
while (sequence != 1) {
condA.await();
}
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + ": AAA");
sequence = 2;
condB.signal();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
}
public void printB() {
lock.lock();
try {
while (sequence != 2) {
condB.await();
}
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + ": BBB");
sequence = 3;
condC.signal();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
}
public void printC() {
lock.lock();
try {
while (sequence != 3) {
condC.await();
}
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + ": CCC");
sequence = 1;
condA.signal();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
}
}
主程序启动三个线程分别调用printA、printB、printC方法,利用不同的Condition对象实现了精确的线程调度。相比传统wait/notify机制,这种方式避免了不必要的线程唤醒,提升了系统性能与可控性。