求求你,别再用wait和notify了!(2)

简介: 求求你,别再用wait和notify了!(2)

1.3 使用 Condition

为了解决线程的“假死”问题,我们可以使用 Condition 来尝试实现一下,Condition 是 JUC(java.util.concurrent)包下的类,需要使用 Lock 锁来创建,Condition 提供了 3 个重要的方法:


  • await:对应 wait 方法;


  • signal:对应 notify 方法;


  • signalAllnotifyAll 方法。


Condition 的使用和 wait/notify 类似,也是先获得锁然后在锁中进行等待和唤醒操作,Condition 的基础用法如下:


// 创建 Condition 对象
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
// 加锁
lock.lock();
try {
    // 业务方法....
    // 1.进入等待状态
    condition.await();
    // 2.唤醒操作
    condition.signal();
} catch (InterruptedException e) {
    e.printStackTrace();
} finally {
    lock.unlock();
}



小知识:Lock的正确使用姿势


切记 Locklock.lock() 方法不能放入 try 代码中,如果 lock 方法在 try 代码块之内,可能由于其它方法抛出异常,导致在 finally 代码块中, unlock 对未加锁的对象解锁,它会调用 AQStryRelease 方法(取决于具体实现类),抛出 IllegalMonitorStateException 异常。


回归主题


回到本文的主题,我们如果使用 Condition 来实现线程的通讯就可以避免程序的“假死”情况,因为 Condition 可以创建多个等待集,以本文的生产者和消费者模型为例,我们可以使用两个等待集,一个用做消费者的等待和唤醒,另一个用来唤醒生产者,这样就不会出现生产者唤醒生产者的情况了(生产者只能唤醒消费者,消费者只能唤醒生产者)这样整个流程就不会“假死”了,它的执行流程如下图所示:



微信图片_20220120144754.jpg


了解了它的基本流程之后,咱们来看具体的实现代码。

基于 Condition 的工厂实现代码如下:


class FactoryByCondition {
    private int[] items = new int[1]; // 数据存储容器(为了演示方便,设置容量最多存储 1 个元素)
    private int size = 0;             // 实际存储大小
    // 创建 Condition 对象
    private Lock lock = new ReentrantLock();
    // 生产者的 Condition 对象
    private Condition producerCondition = lock.newCondition();
    // 消费者的 Condition 对象
    private Condition consumerCondition = lock.newCondition();
    /**
     * 生产方法
     */
    public void put() throws InterruptedException {
        // 循环生产数据
        do {
            lock.lock();
            while (size == items.length) { // 注意不能是 if 判断
                // 生产者进入等待
                System.out.println(Thread.currentThread().getName() + " 进入阻塞");
                producerCondition.await();
                System.out.println(Thread.currentThread().getName() + " 被唤醒");
            }
            System.out.println(Thread.currentThread().getName() + " 开始工作");
            items[0] = 1; // 为了方便演示,设置固定值
            size++;
            System.out.println(Thread.currentThread().getName() + " 完成工作");
            // 唤醒消费者
            consumerCondition.signal();
            try {
            } finally {
                lock.unlock();
            }
        } while (true);
    }
    /**
     * 消费方法
     */
    public void take() throws InterruptedException {
        // 循环消费数据
        do {
            lock.lock();
            while (size == 0) {
                // 消费者阻塞等待
                consumerCondition.await();
            }
            System.out.println("消费者工作~");
            size--;
            // 唤醒生产者
            producerCondition.signal();
            try {
            } finally {
                lock.unlock();
            }
        } while (true);
    }
}




相关文章
|
12天前
|
安全 Java 开发者
深入解读JAVA多线程:wait()、notify()、notifyAll()的奥秘
在Java多线程编程中,`wait()`、`notify()`和`notifyAll()`方法是实现线程间通信和同步的关键机制。这些方法定义在`java.lang.Object`类中,每个Java对象都可以作为线程间通信的媒介。本文将详细解析这三个方法的使用方法和最佳实践,帮助开发者更高效地进行多线程编程。 示例代码展示了如何在同步方法中使用这些方法,确保线程安全和高效的通信。
37 9
|
5月前
|
Java 程序员
从菜鸟到大神:JAVA多线程通信的wait()、notify()、notifyAll()之旅
【6月更文挑战第21天】Java多线程核心在于wait(), notify(), notifyAll(),它们用于线程间通信与同步,确保数据一致性。wait()让线程释放锁并等待,notify()唤醒一个等待线程,notifyAll()唤醒所有线程。这些方法在解决生产者-消费者问题等场景中扮演关键角色,是程序员从新手到专家进阶的必经之路。通过学习和实践,每个程序员都能在多线程编程的挑战中成长。
56 6
|
5月前
|
安全 Java
JAVA多线程通信新解:wait()、notify()、notifyAll()的实用技巧
【6月更文挑战第20天】Java多线程中,`wait()`, `notify()`和`notifyAll()`用于线程通信。在生产者-消费者模型示例中,它们确保线程同步。`synchronized`保证安全,`wait()`在循环内防止虚假唤醒,`notifyAll()`避免唤醒单一线程问题。关键技巧包括:循环内调用`wait()`,优先使用`notifyAll()`以保证可靠性,以及确保线程安全和正确处理`InterruptedException`。
52 0
|
1月前
|
调度
【多线程-从零开始-陆】wait、notify和notifyAll
【多线程-从零开始-陆】wait、notify和notifyAll
28 0
|
5月前
|
Java
JAVA多线程的“心灵感应”:wait()与notify()的秘密
【6月更文挑战第20天】Java多线程中,`wait()`和`notify()`是线程间协作的关键。它们充当线程间的通信桥梁,使得线程能感知对方状态。例如,生产者线程在资源满时`wait()`,消费者线程消费后`notify()`或`notifyAll()`,确保资源有效利用且避免冲突。简化的代码示例展示了这种同步机制,线程通过等待和唤醒操作实现“心灵感应”般的协同工作。
31 3
|
5月前
|
Java
wait()和notify():JAVA多线程世界的“信号兵”
【6月更文挑战第20天】在Java多线程中,`wait()`和`notify()`作为Object类的方法,扮演着线程间协调者的角色。`wait()`让线程等待并释放锁,`notify()`或`notifyAll()`唤醒等待的线程。在生产者-消费者模型中,它们用于同步访问资源,例如队列。当队列满或空时,线程调用wait()暂停,另一方完成操作后用notify()唤醒。理解并正确使用这些“信号兵”对构建高效的多线程程序至关重要。
33 0
|
5月前
|
Java 开发者
JAVA多线程通信入门:wait()、notify()、notifyAll()大揭秘!
【6月更文挑战第20天】Java多线程中,`wait()`, `notify()`, `notifyAll()`是Object类的关键通信方法。`wait()`让线程等待并释放锁,`notify()`随机唤醒一个等待的线程,`notifyAll()`唤醒所有。示例展示了在共享资源类中如何使用它们来协调生产者消费者线程。调用前需持有锁,否则抛异常。注意避免死锁和活锁,恰当使用这些方法至关重要。
53 0
|
6月前
|
Java 调度
多线程(初阶五:wait和notify)
多线程(初阶五:wait和notify)
84 0
无聊小知识.03 wait(),notify()虚假唤醒
无聊小知识.03 wait(),notify()虚假唤醒
139 0
无聊小知识.03 wait(),notify()虚假唤醒
|
存储 Java API
面试官:为什么 wait/notify 必须与 synchronized 一起使用??
面试官:为什么 wait/notify 必须与 synchronized 一起使用??
165 0
面试官:为什么 wait/notify 必须与 synchronized 一起使用??