深入理解Java多線程中的 wait() 和 notify():為何要與 synchronized 手牽手

在Java中,wait、notify方法通常與synchronized關鍵字一起使用,這樣做有幾個重要的原因,主要涉及線程的協調和正確的并發控制。以下是一些關鍵點:

  1. 監視器鎖(Monitor Lock)

    • 每個對象在Java中都可以作為一個監視器鎖,用來管理對該對象的同步訪問。當一個線程持有一個對象的監視器鎖時,其他線程無法同時獲取這個鎖。
    • wait方法必須在持有監視器鎖的情況下調用,也就是說,wait方法必須在synchronized塊或synchronized方法中調用。調用wait方法的線程會放棄該對象的監視器鎖,同時進入等待狀態,直到另一個線程調用同一對象上的notifynotifyAll方法。
  2. 釋放鎖和等待

    • 當一個線程調用對象的wait方法時,它會釋放該對象的監視器鎖,并等待被喚醒。如果沒有synchronized關鍵字保證線程在調用wait方法時已經持有鎖,就無法確保線程在進入等待狀態前不會與其他線程發生競爭條件(race condition)。
    • 只有持有監視器鎖的線程才能調用wait方法,這樣可以確保在進入等待狀態之前不會有其他線程修改共享資源,從而避免不一致的狀態。
  3. 線程協調

    • waitnotifynotifyAll方法提供了一種線程間通信的機制,使得一個線程可以通過這些方法來通知其他線程某些條件已經滿足。
    • synchronized關鍵字確保了只有一個線程能夠在某個時間段內執行持有相同監視器鎖的代碼,從而避免多個線程同時修改共享資源導致的數據不一致問題。

簡而言之,wait方法需要與synchronized一起使用,以確保線程在進入等待狀態之前,已經安全地獲取了監視器鎖,并且在被喚醒后能夠重新獲得鎖。這種機制確保了線程間的協調和共享資源的一致性。

舉個簡單的例子說明:

class SharedResource {private boolean condition = false;public synchronized void waitForCondition() throws InterruptedException {while (!condition) {wait();}// do something after condition is true}public synchronized void changeCondition() {condition = true;notify(); // or notifyAll();}
}

在這個例子中,waitForCondition方法使用synchronized關鍵字來獲取鎖,然后調用wait方法。當changeCondition方法改變條件并調用notifynotifyAll方法時,等待的線程將被喚醒并繼續執行,同時它們會重新獲取鎖。

再寫一段代碼

/*** 功能描述:  Java多線程中的 wait() 和 notify() 方法* @author Songxianyang* @date 2024-06-25 17:38*/
public class WaitNotify {public void waitTest(Object lock) throws InterruptedException {synchronized (lock) {lock.wait();System.out.println("線程等待!!!釋放鎖等待----"+Thread.currentThread().getName());}}@SneakyThrowsprivate void notifyTest(Object lock) {synchronized (lock) {// lock.notify();lock.notifyAll();System.out.println("喚醒線程呀哈哈哈---(喚醒其中一個線程,去槍鎖)"+Thread.currentThread().getName());TimeUnit.SECONDS.sleep(2);}}public static void main(String[] args) {Object lock = new Object();Thread thread = new Thread(()->{WaitNotify waitNotify = new WaitNotify();try {waitNotify.waitTest(lock);} catch (InterruptedException e) {e.printStackTrace();}},"線程1");thread.start();Thread thread2 = new Thread(()->{WaitNotify waitNotify = new WaitNotify();try {waitNotify.waitTest(lock);} catch (InterruptedException e) {e.printStackTrace();}},"線程2");thread2.start();Thread thread3 = new Thread(()->{WaitNotify waitNotify = new WaitNotify();waitNotify.notifyTest(lock);},"線程3");thread3.start();}
}

上面得例子可得:

  • 方法notify()也要在同步方法或同步塊中調用,該方法是用來通知那些可能等待該對象的對象鎖的其它線程,對其發出通知notify,并使它們重新獲取該對象的對象鎖。

  • 如果有多個線程等待,則有線程調度器隨機挑選出一個呈 wait 狀態的線程。(并沒有 “先來后到”)

  • 在notify()方法后,當前線程不會馬上釋放該對象鎖,要等到執行notify()方法的線程將程序執行完,也就是退出同步代碼塊之后才會釋放對象鎖。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/35673.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/35673.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/35673.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

二叉樹 遍歷迭代法

二叉樹 遍歷迭代法 Leetcode 94 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), rig…

一個產品需求工程師繁忙的一天

早晨:開啟新的一天 7:00 AM - 起床 早晨七點準時起床。洗漱、早餐后,查看手機上的郵件和消息,提前了解今天的工作安排和優先事項。 8:00 AM - 前往公司 坐地鐵前往公司。在地鐵上,習慣性地閱讀一些行業資訊和市場報告&#xff0…

使用SpringBoot整合Servlet

一、SpringBoot和Servlet的整合 1、用注解WebServlet配置Servlet映射 創建一個SpringBoot的web工程,在工程用創建一個Servlet 2、在SpringBoot的啟動類上加注解ServletComponentScan 二、額外的方式 1、不使用WebServlet配置Servlet映射 創建一個SpringBoot工…

RabbitMQ延時隊列(實現定時任務)

消息的TTL(Time To Live)就是消息的存活時間。 RabbitMQ可以對隊列和消息分別設置TTL。 對隊列設置存活時間,就是隊列沒有消費者連著的保留時間。 對每一個單獨的消息單獨的設置存活時間。超過了這個時間,我們認為這個消息就死了,稱之為死…

代碼隨想錄算法訓練營:19/60

非科班學習算法day19 | LeetCode530:二叉搜索樹的最小絕對差 ,Leetcode501:二叉搜索樹的眾數 ,Leetcode236:二叉樹的最近公共祖先 目錄 介紹 一、LeetCode題目 1.LeetCode530:二叉搜索樹的最小絕對差 題目解析 2.Leetcode501: 二叉搜索樹的眾數 …

軟設之加工邏輯之結構化語言

結構化語言是一種介于自然語言和形式化語言之間的半形式語言,是自然語言的一個受限子集 外層:用來描述控制結構,采用順序,選擇和重復3種基本結構 1.順序結構:一組祈使語句,選擇語句,重復語句的…

個人對JVM的一點理解

JVM(Java 虛擬機)是 Java 程序能夠跨平臺運行的關鍵。它負責將 Java 字節碼轉換為機器碼并執行。 JVM 主要由類加載器、運行時數據區、執行引擎和本地方法接口等部分組成。運行時數據區包括方法區、堆、虛擬機棧、本地方法棧和程序計數器等。 GC&#xf…

遠期利率(Forward Rate)是什么?以及遠期利率在期貨合約中的應用

遠期利率是什么? 中文版 遠期利率(Forward Rate)是指從未來某一時間段開始適用的利率。它是金融市場上的一種合約利率,表示在某個特定日期開始的一段時間內的預期利率。這種利率可以通過現有的即期利率(Spot Rate&am…

6.26考試前總結

一、選擇 1、運算符重載:(1)不可重載:. .* :: ?: sizeof (2)只成員函數:、[]、()、-> ps:和[]需要加&,返回類,[]返回中括號內…

SpringBoot根據不同IP限制接口的QPS

根據對方IP地址來限制接口的QPS(每秒查詢率),你可以結合Spring Boot應用、Guava的RateLimiter或者自定義的并發控制邏輯來實現。以下是一個基于Guava RateLimiter和Spring Boot的示例,展示如何根據IP地址來限制接口的QPS&#xff…

鏡頭下的光學

說實話,當我看到幾何光學的內容全是初中的解析幾何的時候,我就覺得講的方式太原始了,而且太過復雜也看不懂。所以我嘗試做了數學建模,發現建模之后模型可以解釋一些物理現象,也不會有矛盾的地方,那就算過得…

【Python系列】探索 Python 環境管理工具:conda 與 pip 的比較

💝💝💝歡迎來到我的博客,很高興能夠在這里和您見面!希望您在這里可以感受到一份輕松愉快的氛圍,不僅可以獲得有趣的內容和知識,也可以暢所欲言、分享您的想法和見解。 推薦:kwan 的首頁,持續學…

簡過網:專科生可以考的編制崗位有哪些?這5個鐵飯碗要抓住了!

專科生可以考的編制崗位有哪些?以下這幾種可以考的,尤其是應屆畢業生,一定要抓住機會哦! ? 一、三支一扶:專科生可報考,期滿可轉編。 三支一扶:支農、支醫生、支教、扶貧 工作時間一般為2年&…

深入探索Postman:前置與后置腳本的編寫與應用

Postman是一款廣受歡迎的API開發和測試工具,它提供了豐富的功能來簡化接口測試過程。在Postman中,前置腳本(Pre-request Script)和后置腳本(Tests Script)是兩個強大的功能,允許用戶在發送請求之…

秋招Java后端開發沖刺——非關系型數據庫篇(Redis)

一、非關系型數據庫 1. 主要針對的是鍵值、文檔以及圖形類型數據存儲。 2. 特點: 特點說明靈活的數據模型支持多種數據模型(文檔、鍵值、列族、圖),無需預定義固定的表結構,能夠處理各種類型的數據。高擴展性設計為水…

安全技術和防火墻(一)

安全技術和防火墻 安全技術 入侵檢測系統:特點是不阻斷網絡訪問,主要提供報警和事后監督 不主動介入 (監控) 入侵防御系統:透明模式工作 ,數據包,網絡監控,服務攻擊,木馬,蠕蟲,系統漏洞 等 進行準確的分析判斷 判斷為攻擊行為后會…

高校心理咨詢管理系統

摘 要 隨著高校學生心理問題的增多,心理咨詢服務在高校中的重要性日益凸顯。然而,傳統的心理咨詢管理方式存在著諸多問題,如信息不透明、咨詢師資源不足等。為了解決這些問題,本文設計并實現了一種基于Java Web的高校心理咨詢管理…

model_json_schema

model_json_schema示列 from pydantic import BaseModel, Field, ValidationError, field_validatorclass User(BaseModel):id: int Field(default0, lt100, gt0)username: stremail: strfield_validator(username)def name_must_alpha(cls, v):assert v.isalpha(), name mus…

浸式冷卻設計參數

每天一篇行業發展資訊,讓大家更及時了解外面的世界。 更多資訊,請關注B站/公眾號【萊歌數字】,有視頻教程~~ 兩相被動浸入冷卻是指使用改變相的沸騰液體來去除一個或多個表面的熱量的冷卻系統。 然后蒸汽被移動到冷凝器,然后被…

LaTeX中添加矩陣分塊虛線并設置虛線疏密

對于大型矩陣,有時需要添加分塊虛線。 方法為使用arydshln宏包,然后在array環境中設置虛線。需要注意的是,使用矩陣環境需要搭配amsmath宏包使用,且需放在amsmath宏包之后。即導言區設置為 \usepackage{amsmath} \usepackage{ary…