wait()和notify()、notifyAll()
来源:互联网 发布:知乎数据接口 编辑:程序博客网 时间:2024/05/16 17:18
今天想到了这个问题(wait()方法、notify()、notifyAll()这三个方法是不是执行了就释放锁呢?答案是:都会释放锁
- 为什么 wait(), notify()和 和 notifyAll()必须在同步方法或者同步块中 必须在同步方法或者同步块中被调用?
答:当一个线程需要调用对象的 wait()方法的时候,这个线程必须拥有该对象的锁,接着它就会释放这个对象锁并进入等待状态直到其他线程调用这个对象上的 notify()方法。同样的,当一个线程需要调用对象的 notify()方法时,它会释放这个对象的锁,以便其他在等待的线程就可以得到这个对象锁。由于所有的这些方法都需要线程持有对象的锁,这样就只能通过同步来实现,所以他们只能在同步方法或者同步块中被调用。
另外,notify()可能会引发死锁问题,而notifyAll()不会,具体参照点击进入
==========================
下面讲一个在练习的时候发现的知识点:
下面是一段生产者消费者模式程序:
Account类:
package cn.review.waitNotify.three;public class Account { private String accountNo; private Double balance; public Account(String accountNo, double balance){ this.accountNo = accountNo; this.balance = balance; } private boolean flag_draw; public String getAccountNo() { return accountNo; } public double getBalance() { return balance; } //取钱 public synchronized void draw(double money){ if(!flag_draw){ //如果flag_draw表名账户还没人存进去 try { balance.wait(); //锁的是整个account对象 } catch (InterruptedException e) { e.printStackTrace(); } }else{ balance = balance - money; System.out.println(Thread.currentThread().getName()+" 取出"+money+"元,余额是"+balance+"元"); flag_draw = false; balance.notifyAll(); } } //存钱 public synchronized void deposit(double money){ if(flag_draw){ try { balance.wait(); } catch (InterruptedException e) { e.printStackTrace(); } }else{ balance = balance + money; System.out.println(Thread.currentThread().getName()+" 存入"+money+"元,余额是"+balance+"元"); flag_draw = true; balance.notifyAll(); } }}
生产者(存钱的人)类:
package cn.review.waitNotify.three;public class Producer implements Runnable{ private Account account; private double depositMoney; public Account getAccount() { return account; } public double getDepositMoney() { return depositMoney; } public void setDepositMoney(double depositMoney) { this.depositMoney = depositMoney; } public Producer(Account account, double depositMoney){ this.account = account; this.depositMoney = depositMoney; } @Override public void run() { //进行100次存钱 for(int i = 0; i < 100; i++){ account.deposit(depositMoney); } }}
消费者(取钱的人)类:
package cn.review.waitNotify.three;public class Consumer implements Runnable{ private Account account; private double drawMoney; public Consumer(Account account, double drawMoney){ this.account = account; this.drawMoney = drawMoney; } public Account getAccount() { return account; } public double getDrawMoney() { return drawMoney; } @Override public void run() { //进行100次取款 for(int i = 0; i < 100; i++){ account.draw(drawMoney); } }}
测试类:
package cn.review.waitNotify.three;public class Test1 { public static void main(String[] args) { Account account = new Account("212212", 1000); Producer p1 = new Producer(account, 100); Consumer c1 = new Consumer(account, 80); Consumer c2 = new Consumer(account, 80); new Thread(p1, "存钱者").start(); new Thread(c1, "取前者1").start(); new Thread(c2, "取前者2").start(); }}
测试类中另开3条线程,其中1条生产者,2条消费者。每个线程都进行100次的存钱或取钱,在Account类中保证了一个账户不能进行连续的存钱或者取钱,运行得到的结果是:
存钱者 存入100.0元,余额是1100.0元取前者2 取出80.0元,余额是1020.0元存钱者 存入100.0元,余额是1120.0元取前者1 取出80.0元,余额是1040.0元存钱者 存入100.0元,余额是1140.0元取前者2 取出80.0元,余额是1060.0元存钱者 存入100.0元,余额是1160.0元取前者1 取出80.0元,余额是1080.0元存钱者 存入100.0元,余额是1180.0元取前者2 取出80.0元,余额是1100.0元存钱者 存入100.0元,余额是1200.0元取前者1 取出80.0元,余额是1120.0元......
程序最后处于不输出任何数据状态(注意这不是死锁)。。
以上一切都很正常,当我把Account类的取钱方法和存钱方法改为:
取钱方法:
//取钱 public void draw(double money){ synchronized (balance) { if(!flag_draw){ //如果flag_draw表名账户还没人存进去 try { balance.wait(); //锁的是整个account对象 } catch (InterruptedException e) { e.printStackTrace(); } }else{ balance = balance - money; System.out.println(Thread.currentThread().getName()+" 取出"+money+"元,余额是"+balance+"元"); flag_draw = false; balance.notifyAll(); } } }
存钱方法:
//存钱 public void deposit(double money){ synchronized (balance) { if(flag_draw){ try { balance.wait(); } catch (InterruptedException e) { e.printStackTrace(); } }else{ balance = balance + money; System.out.println(Thread.currentThread().getName()+" 存入"+money+"元,余额是"+balance+"元"); flag_draw = true; balance.notifyAll(); } } }
则会出现以下结果:
存钱者 存入100.0元,余额是1100.0元Exception in thread "存钱者" java.lang.IllegalMonitorStateException at java.lang.Object.notifyAll(Native Method) at cn.review.waitNotify.three.Account.deposit(Account.java:53) at cn.review.waitNotify.three.Producer.run(Producer.java:26) at java.lang.Thread.run(Thread.java:619)
百度了下,报IllegalMonitorStateException的原因是:
首先你要了解这个异常为什么会抛出,这个异常会在三种情况下抛出:
1>当前线程不含有当前对象的锁资源的时候,调用obj.wait()方法;
2>当前线程不含有当前对象的锁资源的时候,调用obj.notify()方法。
3>当前线程不含有当前对象的锁资源的时候,调用obj.notifyAll()方法。
后来我把balance+=money
去掉了,程序又恢复正常了。原因是这样的, 当线程进入临界区时,获得了balance的对象所,而在Account类中,balance是Double类型的,而Double类型是不可变类,它与String一样,也就是当进行balance+=money
时,已经将balance的实例改变了,再也不指向原来的Double对象了,这时候进行balance.wait()
或balance.notify()
或balance.notifyAll()
; 就自然会报错。
重点记下:Double、Integer、Character等是不可变类。wait()、notify()、notifyAll()在同步代码块里面使用,
- wait()和notify()/notifyAll()
- wait()和notify()、notifyAll()
- wait、notify、notifyAll和Condition
- java wait()、notify()和notifyAll()
- wait, notify 和 notifyAll 使用
- wait, notify 和 notifyAll区别
- JAVA的wait和notify和notifyall
- wait和notify以及notifyAll的使用方法
- Java多线程3:wait、notify和notifyAll
- wait / notify / notifyAll 和 synchronized method / block
- Java Thread wait, notify和notifyAll示例
- Java之wait()/sleep()和notify()/notifyAll()
- Java 中的 wait(), notify ()和 notifyAll ()
- Java多线程8:wait()和notify()/notifyAll()
- java多线程之wait、notify和notifyAll
- Java并发编程:wait()和notify()/notifyAll()
- 浅谈synchronized、wait、notify和notifyAll
- 多线程之wait()、notify()和notifyAll()
- Android一些重要的工具类
- Apache的prefork模式和worker模式
- 谭浩强C程序设计第三版习题7.15
- 第五周项目二 建立链栈算法库
- bzoj2661(网络流)
- wait()和notify()、notifyAll()
- jointJS(二)--jointJS官方版本的一个改造bottomtopmodel
- 自定义弧形进度条
- C#接口和类有什么异同。
- POJ 3295 Tautology(构造)(栈)
- 插入排序(希尔排序、直接插入、折半插入排序)
- RE:从零开始的数据结构生活
- September 24th 模拟赛C T2 序列和 Solution
- G - N!Again