成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

為什么 Wait 和 Notify 必須放在 Synchronized 中?

開發 前端
在 Java 中,wait 和 notify/notifyAll 有著一套自己的使用格式要求,也就是在使用 wait 和 notify(notifyAll 的使用和 notify 類似,所以下文就只用 notify 用來指代二者)必須配合 synchronized 一起使用才行。

在多線程編程中,wait 方法是讓當前線程進入休眠狀態,直到另一個線程調用了 notify 或 notifyAll 方法之后,才能繼續恢復執行。而在 Java 中,wait 和 notify/notifyAll 有著一套自己的使用格式要求,也就是在使用 wait 和 notify(notifyAll 的使用和 notify 類似,所以下文就只用 notify 用來指代二者)必須配合 synchronized 一起使用才行。

wait/notify基礎使用

wait 和 notify 的基礎方法如下:

Object lock = new Object();
new Thread(() -> {
synchronized (lock) {
try {
System.out.println("wait 之前");
// 調用 wait 方法
lock.wait();
System.out.println("wait 之后");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();

Thread.sleep(100);
synchronized (lock) {
System.out.println("執行 notify");
// 調用 notify 方法
lock.notify();
}

以上代碼的執行結果如下圖所示:

wait/notify和synchronized一起用?

那問題來了,是不是 wait 和 notify 一定要配合 synchronized 一起使用呢?wait 和 notify 單獨使用行不行呢?我們嘗試將以上代碼中的 synchronized 代碼行刪除,實現代碼如下:

初看代碼好像沒啥問題,編譯器也沒報錯,好像能“正常使用”,然而當我們運行以上程序時就會發生如下錯誤:

從上述結果可以看出:無論是 wait 還是 notify,如果不配合 synchronized 一起使用,在程序運行時就會報 IllegalMonitorStateException 非法的監視器狀態異常,而且 notify 也不能實現程序的喚醒功能了。

原因分析

從上述的報錯信息我們可以看出,JVM 在運行時會強制檢查 wait 和 notify 有沒有在 synchronized 代碼中,如果沒有的話就會報非法監視器狀態異常(IllegalMonitorStateException),但這也僅僅是運行時的程序表象,那為什么 Java 要這樣設計呢?其實這樣設計的原因就是為了防止多線程并發運行時,程序的執行混亂問題。初看這句話,好像是用來描述“鎖”的。然而實際情況也是如此,wait 和 notify 引入鎖就是來規避并發執行時程序的執行混亂問題的。那這個“執行混亂問題”到底是啥呢?接下來我們繼續往下看。

wait和notify問題復現

我們假設 wait 和 notify 可以不加鎖,我們用它們來實現一個自定義阻塞隊列。這里的阻塞隊列是指讀操作阻塞,也就是當讀取數據時,如果有數據就返回數據,如果沒有數據則阻塞等待數據,實現代碼如下:

class MyBlockingQueue {
// 用來保存數據的集合
Queue<String> queue = new LinkedList<>();

/**
* 添加方法
*/
public void put(String data) {
// 隊列加入數據
queue.add(data);
// 喚醒線程繼續執行(這里的線程指的是執行 take 方法的線程)
notify(); //
}

/**
* 獲取方法(阻塞式執行)
* 如果隊列里面有數據則返回數據,如果沒有數據就阻塞等待數據
* @return
*/
public String take() throws InterruptedException {
// 使用 while 判斷是否有數據(這里使用 while 而非 if 是為了防止虛假喚醒)
while (queue.isEmpty()) { //
// 沒有任務,先阻塞等待
wait(); //
}
return queue.remove(); // 返回數據
}
}

注意上述代碼,我們在代碼中標識了三個關鍵執行步驟:①:判斷隊列中是否有數據;②:執行 wait 休眠操作;③:給隊列中添加數據并喚醒阻塞線程。如果不強制要求添加 synchronized,那么就會出現如下問題:

步驟

線程1

線程2

1

執行步驟 ① 判斷當前隊列中沒有數據


2


執行步驟 ③ 將數據添加到隊列,并喚醒線程1繼續執行

3

執行步驟 ② 線程 1 進入休眠狀態

從上述執行流程看出問題了嗎?如果 wait 和 notify 不強制要求加鎖,那么在線程 1 執行完判斷之后,尚未執行休眠之前,此時另一個線程添加數據到隊列中。然而這時線程 1 已經執行過判斷了,所以就會直接進入休眠狀態,從而導致隊列中的那條數據永久性不能被讀取,這就是程序并發運行時“執行結果混亂”的問題。然而如果配合 synchronized 一起使用的話,代碼就會變成以下這樣:

class MyBlockingQueue {
// 用來保存任務的集合
Queue<String> queue = new LinkedList<>();

/**
* 添加方法
*/
public void put(String data) {
synchronized (MyBlockingQueue.class) {
// 隊列加入數據
queue.add(data);
// 為了防止 take 方法阻塞休眠,這里需要調用喚醒方法 notify
notify(); //
}
}

/**
* 獲取方法(阻塞式執行)
* 如果隊列里面有數據則返回數據,如果沒有數據就阻塞等待數據
* @return
*/
public String take() throws InterruptedException {
synchronized (MyBlockingQueue.class) {
// 使用 while 判斷是否有數據(這里使用 while 而非 if 是為了防止虛假喚醒)
while (queue.isEmpty()) { //
// 沒有任務,先阻塞等待
wait(); //
}
}
return queue.remove(); // 返回數據
}
}

這樣改造之后,關鍵步驟 ① 和關鍵步驟 ② 就可以一起執行了,從而當線程執行了步驟 ③ 之后,線程 1 就可以讀取到隊列中的那條數據了,它們的執行流程如下:

步驟

線程1

線程2

1

執行步驟 ① 判斷當前隊列沒有數據


2

執行步驟 ② 線程進入休眠狀態


3


執行步驟 ③ 將數據添加到隊列,并執行喚醒操作

4

線程被喚醒,繼續執行


5

判斷隊列中有數據,返回數據


這樣咱們的程序就可以正常執行了,這就是為什么 Java 設計一定要讓 wait 和 notify 配合上 synchronized 一起使用的原因了。

總結

本文介紹了 wait 和 notify 的基礎使用,以及為什么 wait 和 notify/notifyAll 一定要配合 synchronized 使用的原因。如果 wait 和 notify/notifyAll 不強制和 synchronized 一起使用,那么在多線程執行時,就會出現 wait 執行了一半,然后又執行了添加數據和 notify 的操作,從而導致線程一直休眠的缺陷。


責任編輯:武曉燕 來源: Java面試真題解析
相關推薦

2020-12-15 08:06:45

waitnotifyCondition

2015-08-05 09:33:21

Javawaitnotify

2010-03-15 18:25:27

Java編程語言

2023-10-12 07:35:45

面試線程通信

2025-01-09 08:49:36

Java并發編程

2022-04-02 14:13:12

身份驗證軟件開發低代碼

2015-04-03 12:31:26

OracleSalesforce并購

2019-11-17 22:38:13

PAM特權訪問管理CISO

2023-11-26 00:24:33

2014-07-02 16:51:08

WOT2014高效技術團隊

2010-08-12 10:54:26

惠普

2022-09-21 14:44:39

邊緣計算人工智能

2021-12-17 22:56:27

前端測試框架

2021-02-28 13:22:29

物聯網5G技術

2021-07-10 08:37:36

Notify機制Java

2022-04-02 09:32:06

大數據數據智能企業

2023-12-19 07:56:08

微服務軟件測試左移測試

2021-04-25 09:23:43

XDRMDR網絡安全

2017-01-11 14:19:26

JVM源碼All

2024-10-12 14:58:07

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 91美女在线观看 | 成人欧美一区二区 | 国产成人免费视频网站视频社区 | 91精品久久久久久久久 | 精品麻豆剧传媒av国产九九九 | 午夜视频一区二区三区 | 91网站在线观看视频 | 天堂一区在线 | 色精品| 99久久婷婷国产综合精品电影 | 国产一区二区三区在线看 | 人人干人人看 | 色999视频 | 九九九久久国产免费 | 日本天堂视频在线观看 | 亚洲国产一区二区视频 | 一级黄色日本片 | 一区二区免费 | 国产伦精品一区二区三区照片91 | 欧美综合一区二区三区 | 久久精品国产久精国产 | a级大毛片| 精品日韩一区二区三区 | 免费在线观看av网站 | www.天天操| 美女三区| 成人精品在线观看 | 成人精品国产 | 九九综合| 日韩一区中文字幕 | 久久九九影视 | 欧美激情视频一区二区三区在线播放 | 国产福利91精品 | 国产1区2区3区 | 91中文字幕在线观看 | 久久777 | 国产一区亚洲二区三区 | 欧美日韩亚洲系列 | 综合自拍| 精品一区二区久久久久久久网站 | 天堂素人约啪 |