關(guān)于notify()和notifyAll()方法的用法與區(qū)別
一、區(qū)別
notify()和notifyAll()都是用來用來喚醒調(diào)用wait()方法進(jìn)入等待鎖資源隊(duì)列的線程,區(qū)別在于:
notify()
- 喚醒正在等待此對象監(jiān)視器的單個(gè)線程。
- 如果有多個(gè)線程在等待,則選擇其中一個(gè)隨機(jī)喚醒(由調(diào)度器決定),喚醒的線程享有公平競爭資源的權(quán)利
notifyAll()
- 喚醒正在等待此對象監(jiān)視器的所有線程,喚醒的所有線程公平競爭資源
二、示例
notify()
public class ThreadDemo implements Runnable{
static Object lock = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(new ThreadDemo(), "Thread-a");
Thread thread2 = new Thread(new ThreadDemo(), "Thread-b");
thread1.start();
thread2.start();
try {
TimeUnit.SECONDS.sleep(1); // 睡會(huì),讓走到子線程
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " 獲得了鎖");
System.out.println("notify前" + thread1.getName() + "狀態(tài)是" + thread1.getState());
System.out.println("notify前" + thread2.getName() + "狀態(tài)是 " + thread2.getState());
lock.notify(); // 喚醒一個(gè)等待lock鎖的線程
}
try {
TimeUnit.MILLISECONDS.sleep(300); // 睡會(huì),讓被喚醒的子線程走完
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("notify后" + thread1.getName() + "狀態(tài)是" + thread1.getState());
System.out.println("notify后" + thread2.getName() + "狀態(tài)是" + thread2.getState());
}
@Override
public void run() {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " 獲得了鎖");
try {
lock.wait(); // 等待被喚醒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " end");
}
}
}
結(jié)果:
可以看到,子線程在wait()后釋放了鎖并進(jìn)入WAITTINT狀態(tài),主線程獲得鎖后調(diào)用notify(),這時(shí)候其中一個(gè)線程(栗子中是Thread-b,也有可能是a)被喚醒并獲取到鎖繼續(xù)執(zhí)行到TERMINATED,而另一個(gè)線程a一直WAITTINT狀態(tài)
Thread-b 獲得了鎖 Thread-a 獲得了鎖 main 獲得了鎖 notify前Thread-a狀態(tài)是WAITING notify前Thread-b狀態(tài)是 WAITING Thread-b end notify后Thread-a狀態(tài)是WAITING notify后Thread-b狀態(tài)是TERMINATED
notifyAll()
上面的栗子如果使用notifyAll(),看下結(jié)果
public class ThreadDemo implements Runnable{
static Object lock = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(new ThreadDemo(), "Thread-a");
Thread thread2 = new Thread(new ThreadDemo(), "Thread-b");
thread1.start();
thread2.start();
try {
TimeUnit.SECONDS.sleep(1); // 睡會(huì),讓走到子線程
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("哈哈哈哈");
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " 獲得了鎖");
System.out.println("notify前" + thread1.getName() + "狀態(tài)是" + thread1.getState());
System.out.println("notify前" + thread2.getName() + "狀態(tài)是 " + thread2.getState());
lock.notifyAll(); // 喚醒所有等待lock鎖的線程
}
try {
TimeUnit.MILLISECONDS.sleep(300); // 睡會(huì),讓被喚醒的子線程走完
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("notify后" + thread1.getName() + "狀態(tài)是" + thread1.getState());
System.out.println("notify后" + thread2.getName() + "狀態(tài)是" + thread2.getState());
}
@Override
public void run() {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " 獲得了鎖");
try {
lock.wait(); // 等待被喚醒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " end");
}
}
}
結(jié)果,可以看到所有子線程都被喚醒并再次公平競爭鎖直到線程終止
Thread-b 獲得了鎖 Thread-a 獲得了鎖 哈哈哈哈 main 獲得了鎖 notify前Thread-a狀態(tài)是WAITING notify前Thread-b狀態(tài)是 WAITING Thread-a end Thread-b end notify后Thread-a狀態(tài)是TERMINATED notify后Thread-b狀態(tài)是TERMINATED
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java實(shí)現(xiàn)將txt文件轉(zhuǎn)成xls文件的方法
今天小編就為大家分享一篇Java實(shí)現(xiàn)將txt文件轉(zhuǎn)成xls文件的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-10-10
SpringCloud?Gateway中GatewayFilterChain執(zhí)行流程詳解
Spring?Cloud?Gateway旨在為微服務(wù)架構(gòu)提供一種簡單有效的、統(tǒng)一的?API?路由管理方式。Spring?Cloud?Gateway?作為?Spring?Cloud?生態(tài)系中的網(wǎng)關(guān),它不僅提供統(tǒng)一的路由方式,并且基于?Filter?鏈的方式提供了網(wǎng)關(guān)基本的功能,例如:安全、監(jiān)控/埋點(diǎn)和限流等2022-10-10
idea中acitviti使用acitBPM插件出現(xiàn)亂碼問題及解決方法
這篇文章主要介紹了idea中acitviti使用acitBPM插件出現(xiàn)亂碼問題及解決方法,通過將File Encodings內(nèi)容設(shè)置為UTF-8,本文通過圖文展示,需要的朋友可以參考下2021-06-06
Spring+Mybatis 實(shí)現(xiàn)aop數(shù)據(jù)庫讀寫分離與多數(shù)據(jù)庫源配置操作
這篇文章主要介紹了Spring+Mybatis 實(shí)現(xiàn)aop數(shù)據(jù)庫讀寫分離與多數(shù)據(jù)庫源配置操作,需要的朋友可以參考下2017-09-09
springboot運(yùn)行時(shí)新增/更新外部接口的實(shí)現(xiàn)方法
這篇文章主要介紹了springboot運(yùn)行時(shí)新增/更新外部接口的實(shí)現(xiàn)方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03
Java中實(shí)現(xiàn)Redis管道技術(shù)的代碼詳解
在高并發(fā)的應(yīng)用中,數(shù)據(jù)訪問性能往往是系統(tǒng)性能的關(guān)鍵瓶頸之一,Redis作為一款高性能的內(nèi)存數(shù)據(jù)庫,廣泛應(yīng)用于緩存、會(huì)話存儲(chǔ)等場景,然而,在某些需要執(zhí)行大量Redis命令的場景下,網(wǎng)絡(luò)往返延遲,Redis提供了管道技術(shù)解決這一問題,下面小編給大家詳細(xì)說說2025-04-04

