wait()和notify()、notifyAll()
今天想到了這個問題(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()在同步程式碼塊裡面使用,
相關文章
- sleep & wait | notify | notifyAllAI
- wait、notify和notifyAll的關係AI
- wait/notify/notifyAll 總結AI
- Java-併發-wait()、notify()和notifyAll()JavaAI
- Java的wait(), notify()和notifyAll()使用心得JavaAI
- Java多執行緒8:wait()和notify()/notifyAll()Java執行緒AI
- 如何在 Java 中正確使用 wait, notify 和 notifyAllJavaAI
- 執行緒間協作——wait、notify、notifyAll執行緒AI
- Java常用的三個方法 `wait ` `notify` `notifyAll`JavaAI
- 條件佇列大法好:使用wait、notify和notifyAll的正確姿勢佇列AI
- 執行緒間的同步與通訊(2)——wait, notify, notifyAll執行緒AI
- wait() and notify()AI
- 併發程式設計——執行緒中sleep(),yield(),join(),wait(),notify(),notifyAll()區別程式設計執行緒AI
- 【Java】【多執行緒】兩個執行緒間的通訊、wait、notify、notifyAllJava執行緒AI
- Java 中的 Wait 和 Notify 機制JavaAI
- 併發程式設計之Wait和Notify程式設計AI
- thread的notify和wait怎麼玩?threadAI
- Java多執行緒的wait()和notify()例子Java執行緒AI
- Java 非同步程式設計之:notify 和 wait 用法Java非同步程式設計AI
- Java多執行緒 -- wait() 和 notify() 使用入門Java執行緒AI
- Java同步機制:synchronized,wait,notifyJavasynchronizedAI
- 深入執行緒的wait()/notify()執行緒AI
- Java多執行緒中wait 和 notify 方法理解Java執行緒AI
- 執行緒安全(三個條件)Synchronzied,wait和notify執行緒AI
- java多執行緒wait notify joinJava執行緒AI
- 一個理解wait()與notify()的例子AI
- 條件佇列大法好:wait和notify的基本語義佇列AI
- wait和notify在鎖競爭中的執行順序AI
- java基礎知識回顧之java Thread類學習(七)--java多執行緒通訊等待喚醒機制(wait和notify,notifyAll)...Javathread執行緒AI
- Java通過wait()和notifyAll()方法實現執行緒間的通訊JavaAI執行緒
- 併發-6-wait、notify、Semaphore、CountDownLatch、CyclicBarrierAICountDownLatch
- 多執行緒中的wait與notify執行緒AI
- 一個理解wait()與notify()的例子 (轉)AI
- 多執行緒(一)、基礎概念及notify()和wait()的使用執行緒AI
- 併發程式設計之 wait notify 方法剖析程式設計AI
- java併發程式設計系列:wait/notify機制Java程式設計AI
- 執行緒篇2:[- sleep、wait、notify、join、yield -]執行緒AI
- java多執行緒 wait() notify()簡單使用Java執行緒AI