wait,notify,notifyAll原理以及实际使用场景

简介: wait,notify,notifyAll原理以及实际使用场景

wait : 使当前获取锁的线程挂起。可以选择wait(time,unit) 设置时间和时间单位。

notify : 使当前获取过锁并被wait过的线程由阻塞状态转为就绪状态(随机唤醒)。

notifyAll : 使当前获取过锁并被wait过的所有线程由阻塞状态转为就绪状态。

假设现在系统中有两个线程,这两个线程分别代表存款者和取钱者——现在假设系统有一种特殊的要求,系统要求存款者和取钱者不断地重复存款、取钱的动作,而且要求每当存款者将钱存入指定账户后,取钱者就立即取出该笔钱。不允许存款者连续两次存钱,也不允许取钱者连续两次取钱。

怎么实现呢? 其实可以使用wait,notify,notifyAll 来实现,notifyAll的话可以唤醒所有挂起的线程,取钱者的话我生成了多个例子,因此取钱者就用这个了。notify的话只能随机唤醒一个wait的线程,如果存钱者只有一个的话可以使用notify。但是要注意,一定要对wait过的线程才能使用notify或者notifyAll,否则没有任何意义。

看代码:

账户类

package com.zp.me.thread.wait;
 
import lombok.Data;
 
/**
 * FileName: Account
 * Author:  zp
 * Date:    2022/2022/8/30/20:40
 * Description:
 */
@Data
public class Account {
    private String accountNo;
    private double balance;
 
    public Account() {
    }
 
    public Account(String accountNo, double balance) {
        this.accountNo = accountNo;
        this.balance = balance;
    }
 
    // 如果为true 则代表有存款,取款者可取款,反之存钱者可存钱
    private boolean flag = false;
 
 
    /***
     * @Description: 取钱
     * @Param: [money]
     * @return: void
     * @Author: zp
     * @Date: 2022/8/30
     */
    public synchronized void draw(double money) {
        try {
            if (flag) {
                balance = balance - money;
                System.out.println(Thread.currentThread().getName() + "取了" + money + "元");
                flag = false;
                notifyAll();
            } else {
 
                wait();
 
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
 
    /***
     * @Description: 存钱
     * @Param: [money]
     * @return: void
     * @Author: zp
     * @Date: 2022/8/30
     */
    public synchronized void deposit(double money) {
        try {
            if (flag) {
 
                wait();
 
            } else {
                balance = balance + money;
                System.out.println(Thread.currentThread().getName() + "存了" + money + "元");
                flag = true;
                notify();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
 
 
}

取钱线程

package com.zp.me.thread.wait;
 
import lombok.Data;
 
/**
 * FileName: DrawThread
 * Author:  zp
 * Date:    2022/2022/8/30/20:54
 * Description:
 */
@Data
public class DrawThread extends Thread{
    private Account account;
    private double money;
 
    public DrawThread(String name,Account account, double money) {
        super(name);
        this.account = account;
        this.money = money;
    }
 
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            account.draw(money);
        }
    }
}

存钱线程

package com.zp.me.thread.wait;
 
import lombok.Data;
 
/**
 * FileName: DrawThread
 * Author:  zp
 * Date:    2022/2022/8/30/20:54
 * Description:
 */
@Data
public class DepositThread extends Thread{
    private Account account;
    private double money;
 
    public DepositThread(String name, Account account, double money) {
        super(name);
        this.account = account;
        this.money = money;
    }
 
    @Override
    public void run() {
        for (int i = 0; i < 1; i++) {
            account.deposit(money);
        }
    }
}

测试类

package com.zp.me.thread.wait;
 
/**
 * FileName: ThreadTest
 * Author:  zp
 * Date:    2022/2022/8/30/21:46
 * Description:
 */
public class ThreadTest {
    public static void main(String[] args) {
        Account account = new Account("0000001", 0.00);
        new DepositThread("存钱者1",account,500).start();
        new DrawThread("取钱者1",account,500).start();
        new DrawThread("取钱者2",account,500).start();
        new DrawThread("取钱者3",account,500).start();
 
    }
}

结果:

Connected to the target VM, address: '127.0.0.1:61034', transport: 'socket'
存钱者1存了500.0元
取钱者3取了500.0元

可以看到,不会出现存钱者多存或者取钱者多取的情况。

目录
相关文章
|
监控 安全
并发编程系列教程(06) - 多线程之间通讯(wait、notify、sleep、Lock锁、Condition)
并发编程系列教程(06) - 多线程之间通讯(wait、notify、sleep、Lock锁、Condition)
78 0
|
1月前
|
Java
JAVA多线程通信:为何wait()与notify()如此重要?
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是实现线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件满足时被唤醒,从而确保数据一致性和同步。相比其他通信方式,如忙等待,这些方法更高效灵活。 示例代码展示了如何在生产者-消费者模型中使用这些方法实现线程间的协调和同步。
39 3
|
2月前
|
Java
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件成立时被唤醒,从而有效解决数据一致性和同步问题。本文通过对比其他通信机制,展示了 `wait()` 和 `notify()` 的优势,并通过生产者-消费者模型的示例代码,详细说明了其使用方法和重要性。
41 1
|
6月前
|
Java 开发者
JAVA多线程通信入门:wait()、notify()、notifyAll()大揭秘!
【6月更文挑战第20天】Java多线程中,`wait()`, `notify()`, `notifyAll()`是Object类的关键通信方法。`wait()`让线程等待并释放锁,`notify()`随机唤醒一个等待的线程,`notifyAll()`唤醒所有。示例展示了在共享资源类中如何使用它们来协调生产者消费者线程。调用前需持有锁,否则抛异常。注意避免死锁和活锁,恰当使用这些方法至关重要。
62 0
|
6月前
|
Java
wait()和notify():JAVA多线程世界的“信号兵”
【6月更文挑战第20天】在Java多线程中,`wait()`和`notify()`作为Object类的方法,扮演着线程间协调者的角色。`wait()`让线程等待并释放锁,`notify()`或`notifyAll()`唤醒等待的线程。在生产者-消费者模型中,它们用于同步访问资源,例如队列。当队列满或空时,线程调用wait()暂停,另一方完成操作后用notify()唤醒。理解并正确使用这些“信号兵”对构建高效的多线程程序至关重要。
41 0
|
7月前
|
Java
Java多线程基础-7:wait() 和 notify() 用法解析
这篇内容探讨了Java中的`wait()`和`notify()`方法在多线程编程中的使用。
52 0
|
Java
notify () 和 notifyAll () 的区别
notify () 和 notifyAll () 的区别
193 0
|
7月前
|
Java 调度
多线程(初阶五:wait和notify)
多线程(初阶五:wait和notify)
87 0
|
7月前
|
调度
多线程之wait&notify
多线程之wait&notify