日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

高并发编程-Wait Set 多线程的“休息室”

發(fā)布時(shí)間:2025/3/21 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 高并发编程-Wait Set 多线程的“休息室” 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 概述
  • 關(guān)于wait set
  • 示例
  • 思考

概述

官方指導(dǎo): https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html

或者:

https://learning.oreilly.com/library/view/the-java-language/9780133260335/ch17lev1sec2.html


關(guān)于wait set

  • Every object, in addition to having an associated monitor, has an associated wait set. A wait set is a set of threads.
  • A wait set is a set of threads.
  • When an object is first created, its wait set is empty. Elementary actions that add threads to and remove threads from wait sets are atomic. Wait sets are manipulated solely through the methods Object.wait, Object.notify, and Object.notifyAll.
  • Wait set manipulations can also be affected by the interruption status of a thread, and by the Thread class’s methods dealing with interruption. Additionally, the Thread class’s methods for sleeping and joining other threads have properties derived from those of wait and notification actions.
  • 意思是說(shuō)

  • 每個(gè)對(duì)象除具有關(guān)聯(lián)的監(jiān)視器外,還具有關(guān)聯(lián)wait set。
  • wait set是一組線程
  • 首次創(chuàng)建對(duì)象時(shí),其wait set為空。將線程添加到wait set中或從wait set中刪除線程的基本操作是原子的。wait set完全通過(guò)方法操作Object.wait,Object.notify和Object.notifyAll
  • wait set操作也可能受線程的中斷狀態(tài)以及Thread處理中斷的類(lèi)的方法的影響。此外,Thread該類(lèi)用于休眠和加入其他線程的方法具有從等待和通知操作的屬性派生的屬性。

  • 示例

    package com.artisan.test;import java.util.Optional; import java.util.stream.IntStream;public class WaitSet {// 顯示定義一個(gè)鎖private static final Object LOCK = new Object();public static void main(String[] args) throws InterruptedException {IntStream.rangeClosed(1, 10).forEach(i ->new Thread(String.valueOf("T_" + i)) {@Overridepublic void run() {synchronized (LOCK) {try {Optional.of(Thread.currentThread().getName() + " will come into wait set ..").ifPresent(System.out::println);LOCK.wait();Optional.of(Thread.currentThread().getName() + " will leave from wait set ...").ifPresent(System.out::println);} catch (InterruptedException e) {e.printStackTrace();}}}}.start());// 主線程休眠一秒,確保上面的10個(gè)線程都start ,不然的話 有可能 線程已經(jīng)進(jìn)入wait set ,10個(gè)線程還沒(méi)都啟動(dòng),就已經(jīng)有線程離開(kāi) wait set了Thread.sleep(1_000);System.out.println("=====================10個(gè)線程啟動(dòng)完畢=======================");// 主線程中 每次notify 1個(gè)IntStream.rangeClosed(1, 10).forEach(i -> {synchronized (LOCK) {LOCK.notify();try {// 為了方便觀察 休眠1秒Thread.sleep(1_000);} catch (InterruptedException e) {e.printStackTrace();}}});Thread.sleep(1_000);System.out.println("=====================OVER=======================");}}

    運(yùn)行結(jié)果:

    T_1 will come into wait set .. T_8 will come into wait set .. T_7 will come into wait set .. T_6 will come into wait set .. T_5 will come into wait set .. T_4 will come into wait set .. T_3 will come into wait set .. T_2 will come into wait set .. T_10 will come into wait set .. T_9 will come into wait set .. =====================10個(gè)線程啟動(dòng)完畢======================= T_1 will leave from wait set ... T_8 will leave from wait set ... T_7 will leave from wait set ... T_4 will leave from wait set ... T_5 will leave from wait set ... T_6 will leave from wait set ... T_10 will leave from wait set ... T_2 will leave from wait set ... T_3 will leave from wait set ... T_9 will leave from wait set ... =====================OVER=======================Process finished with exit code 0

    根據(jù)官網(wǎng)和我們的驗(yàn)證,總結(jié)一下

  • 所有的對(duì)象都會(huì)有一個(gè)wait set,用來(lái)存放調(diào)用了該對(duì)象wait方法之后進(jìn)入block狀態(tài)線程
  • 線程被notify之后,不一定立即得到執(zhí)行
  • 線程從wait set中被喚醒順序不一定是FIFO,啥順序,JVM規(guī)范中并沒(méi)有給出,各個(gè)虛擬機(jī)的廠商有各自的實(shí)現(xiàn)

  • 思考

    有個(gè)方法如下:

    private static void anotherThink() {synchronized (LOCK) {System.out.println("anotherThink begin to execute....");try {Optional.of(Thread.currentThread().getName() + " will come into wait set ...").ifPresent(System.out::println);LOCK.wait();} catch (InterruptedException e) {e.printStackTrace();}Optional.of(Thread.currentThread().getName() + " will leave from wait set ...").ifPresent(System.out::println);}}

    Q: 拿到鎖后的第一件事情 是輸出一行日志 anotherThink begin to execute.... 當(dāng)線程1,搶到鎖后 ,調(diào)用wait,放棄了執(zhí)行權(quán)。 如果線程1被喚醒時(shí),肯定要先獲取到鎖才能夠執(zhí)行,那我們剛才說(shuō)的 搶到鎖后打印日志會(huì)不會(huì)被執(zhí)行呢?

    我們來(lái)驗(yàn)證下

    main方法中 測(cè)試代碼如下

    public static void main(String[] args) throws InterruptedException {/** new Thread("Test_Thread") {@Overridepublic void run() {anotherThink();}}.start() **/new Thread(() -> anotherThink() ,"Test Thread").start();Thread.sleep(1000);synchronized (LOCK) {LOCK.notify();}}

    運(yùn)行日志

    根據(jù)測(cè)試結(jié)論可知,是不會(huì)打印第一行的。 而是緊接著wait后面的代碼執(zhí)行,主要是源于JVM內(nèi)部會(huì)記錄上次代碼的執(zhí)行地址,進(jìn)行地址恢復(fù),繼續(xù)執(zhí)行。

    A: 所以線程被喚醒后,必須重新獲取鎖,但是JVM內(nèi)部會(huì)進(jìn)行地址恢復(fù),直接繼續(xù)上次線程后續(xù)的邏輯


    總結(jié)

    以上是生活随笔為你收集整理的高并发编程-Wait Set 多线程的“休息室”的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。