返回

Java并发之Condition: 超越synchronized的等待/通知模式

见解分享

引言

在多线程编程的世界中,同步是至关重要的。它允许线程在共享资源时有序地执行,避免数据损坏和竞争条件。Java语言中提供了多种同步机制,包括内置的synchronized和更高级的LockCondition接口。

synchronized的局限性

synchronized关键字是Java中最早的同步机制,它通过隐式创建监视器对象来实现同步。监视器对象与每个对象关联,当一个线程获取该对象的锁时,它可以独占访问该对象。

然而,synchronized也有其局限性。它使用阻塞式锁,这意味着如果一个线程尝试获取一个已经被另一个线程持有的锁,它将被阻塞,直到该锁被释放。这可能会导致死锁和其他并发问题。

Lock和Condition

LockCondition接口提供了比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的比较

Conditionsynchronized相比有一些优点:

  • 非阻塞: Condition使用非阻塞锁,避免了死锁和线程饥饿的可能性。
  • 更精细的控制: Condition允许线程等待特定条件,而不仅仅是整个对象。
  • 更好的性能: Condition通常比synchronized具有更好的性能,因为它避免了不必要的阻塞。

结论

Condition接口是一个强大的同步机制,它提供了比synchronized更灵活和高效的等待/通知模式。通过使用Condition,开发人员可以创建更健壮、更可扩展的多线程应用程序。

延伸阅读