Java并发之Condition: 超越synchronized的等待/通知模式
2024-01-28 02:02:30
引言
在多线程编程的世界中,同步是至关重要的。它允许线程在共享资源时有序地执行,避免数据损坏和竞争条件。Java语言中提供了多种同步机制,包括内置的synchronized
和更高级的Lock
和Condition
接口。
synchronized的局限性
synchronized
关键字是Java中最早的同步机制,它通过隐式创建监视器对象来实现同步。监视器对象与每个对象关联,当一个线程获取该对象的锁时,它可以独占访问该对象。
然而,synchronized
也有其局限性。它使用阻塞式锁,这意味着如果一个线程尝试获取一个已经被另一个线程持有的锁,它将被阻塞,直到该锁被释放。这可能会导致死锁和其他并发问题。
Lock和Condition
Lock
和Condition
接口提供了比synchronized
更灵活的同步机制。Lock
是一个轻量级的同步原语,它允许线程以非阻塞的方式获取和释放锁。Condition
接口提供了等待和通知机制,允许线程在特定条件满足时等待或唤醒。
Condition的使用
与synchronized
类似,Condition
也与监视器对象关联。线程可以使用await()
方法在条件上等待,直到另一个线程调用signal()
或signalAll()
方法将其唤醒。
例如,考虑以下代码片段:
public class Counter {
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();
}
value++;
condition.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void decrement() {
lock.lock();
try {
while (value == 0) {
condition.await();
}
value--;
condition.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
在这个示例中,Counter
类使用Condition
来实现线程安全的计数器。increment()
方法在计数器为0时等待,而decrement()
方法在计数器大于0时等待。当计数器被修改时,条件被唤醒,允许等待的线程继续执行。
与synchronized的比较
Condition
与synchronized
相比有一些优点:
- 非阻塞:
Condition
使用非阻塞锁,避免了死锁和线程饥饿的可能性。 - 更精细的控制:
Condition
允许线程等待特定条件,而不仅仅是整个对象。 - 更好的性能:
Condition
通常比synchronized
具有更好的性能,因为它避免了不必要的阻塞。
结论
Condition
接口是一个强大的同步机制,它提供了比synchronized
更灵活和高效的等待/通知模式。通过使用Condition
,开发人员可以创建更健壮、更可扩展的多线程应用程序。
延伸阅读