聊聊Object類中的wait()和notify()方法
Object類中的wait()和notify()方法
一、特點
wait()和notify()方法并不是線程對象的方法,是Java中任何一個Java對象都有的方法,并不特殊。
二、wait()方法的作用
Object obj = new Object(); obj.wait();
表示:obj.wait();方法的調(diào)用,會讓“當前線程(正在obj對象上活動的線程)”進入等待狀態(tài)。
三、notify()方法的作用
Object obj = new Object(); obj.notify();
表示:喚醒正在obj對象上等待的線程。
補充:
Object obj = new Object(); obj.notifyAll();
表示:喚醒正在obj對象上等待的所有線程。
四、wait()和notify()的使用
wait()和notify()方法都是建立在synchronized線程同步的基礎(chǔ)之上
重點
obj.wait()方法會讓正在obj對象上活動的當前線程進入等待狀態(tài),并且釋放之前占有的obj對象的鎖。
obj.notify()方法只會通知,不會釋放之前占有的obj對象的鎖。
object中的wait和notify細節(jié)
wait
jdk源碼:
重點看下劃線的地方,是不是有些不理解。有個印象我們繼續(xù)往下看。
public class resourse { private Integer number = 0 ; /** * 用if為啥不行 * 1:首先一點我們要搞清楚 wait操作會釋放鎖 * 2:想想這種情況,當一個生產(chǎn)者線程執(zhí)行的時候 if number!=0 (此時的number為1 ) 就會發(fā)生阻塞 這時候 * 釋放出鎖 這時候又一個生產(chǎn)者進程進來又會被wait住.然后一個生產(chǎn)者進程進來,消費了一個 但是notifyall 將所有的進程 * 都解開了 。。那兩個生產(chǎn)者進程就會直接運行if后面的東西并沒有被拉回來重新判斷一下。這樣就造成了number的值變成2.同理number * 變成負數(shù)也是有可能的(兩個消費者進程先進來都堵塞). * * * * * @throws Exception */ public synchronized void produce () throws Exception { // 判斷 這里用while 用if多與兩個線程容易出錯 // 不等于0就要等待消費者消費完 if(number!=0) { this.wait(); } // 干活 number++; System.out.println(Thread.currentThread().getName() + "的資源數(shù)為:" + number.toString()); // 釋放 this.notifyAll(); } //wait操作會釋放鎖 public synchronized void consumer () throws Exception { // 等于零就要等待生產(chǎn)者生產(chǎn) if (number == 0) { this.wait(); } // 消費 number--; System.out.println(Thread.currentThread().getName() + "的資源數(shù)為:" + number.toString()); // 釋放 this.notifyAll(); } }
調(diào)用者。這里開啟了兩個生產(chǎn)者和兩個消費者線程。生產(chǎn)者線程都執(zhí)行100次的produce,消費者線程都執(zhí)行100次的consumer
public class main { public static void main (String[] args) { resourse resourse = new resourse(); new Thread(()->{ try{ for (int i=0 ; i<100;i++) resourse.produce(); }catch (Exception e) { e.printStackTrace(); } }).start(); new Thread(()->{ try{ for (int i=0 ; i<100;i++) resourse.produce(); }catch (Exception e) { e.printStackTrace(); } }).start(); new Thread(()->{ try{ for (int i=0 ; i<100;i++) resourse.consumer(); }catch (Exception e) { e.printStackTrace(); } }).start(); new Thread(()->{ try{ for (int i=0 ; i<100;i++) resourse.consumer(); }catch (Exception e) { e.printStackTrace(); } }).start(); } }
我要說的重點是:
這樣設(shè)計真的合理嗎?
jdk中為啥要規(guī)定我們要使用while,而不是if?
用if為啥不行
1:首先一點我們要搞清楚 wait操作會釋放鎖
2:想想這種情況,當一個生產(chǎn)者線程執(zhí)行的時候 if number!=0 (此時的number為1 ) 就會發(fā)生阻塞 這時候釋放出鎖 這時候又一個生產(chǎn)者進程進來又會被wait住.然后一個生產(chǎn)者進程進來,消費了一個 但是notifyall 將所有的進程都解開了 。。那兩個生產(chǎn)者進程就會直接運行if后面的東西并沒有被拉回來重新判斷一下。這樣就造成了number的值變成2.同理number變成負數(shù)也是有可能的(兩個消費者進程先進來都堵塞).
這個問題絕對是干貨,在工作中絕對會遇到生產(chǎn)者消費者問題,不少程序員會在這個地方踩坑。面試的時候如果考到你這個地方,你能解答出深層原理來。相信面試官會高看你一眼。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
圖解Java?ReentrantLock的條件變量Condition機制
想必大家都使用過wait()和notify()這兩個方法把,他們主要用于多線程間的協(xié)同處理。而RenentrantLock也支持這樣條件變量的能力,而且相對于synchronized?更加強大,能夠支持多個條件變量,本文就來詳細說說2022-10-10IDEA+Maven搭建Spring環(huán)境的詳細教程
這篇文章主要介紹了IDEA+Maven搭建Spring環(huán)境的詳細教程,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-11-11解決微服務(wù)feign調(diào)用添加token的問題
這篇文章主要介紹了解決微服務(wù)feign調(diào)用添加token的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06