日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

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

文章目錄

  • 概述
  • 關(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.
  • 意思是說

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

  • 示例

    package com.artisan.test;import java.util.Optional; import java.util.stream.IntStream;public class WaitSet {// 顯示定義一個鎖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個線程都start ,不然的話 有可能 線程已經(jīng)進(jìn)入wait set ,10個線程還沒都啟動,就已經(jīng)有線程離開 wait set了Thread.sleep(1_000);System.out.println("=====================10個線程啟動完畢=======================");// 主線程中 每次notify 1個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個線程啟動完畢======================= 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)和我們的驗證,總結(jié)一下

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

  • 思考

    有個方法如下:

    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被喚醒時,肯定要先獲取到鎖才能夠執(zhí)行,那我們剛才說的 搶到鎖后打印日志會不會被執(zhí)行呢?

    我們來驗證下

    main方法中 測試代碼如下

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

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


    總結(jié)

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

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