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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JAVA多线程中wait()方法的详细分析

發布時間:2024/9/30 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JAVA多线程中wait()方法的详细分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載請標明出處:http://blog.csdn.net/zhaoyanjun6/article/details/119645679
本文出自【趙彥軍的博客】

文章目錄

  • wait 和 notify 簡介
  • 對象控制權(monitor)
  • 解題
  • 發散:notify()和notifyAll()
  • 擴展

最近看帖子,發現一道面試題:

啟動兩個線程, 一個輸出 1,3,5,7…99, 另一個輸出 2,4,6,8…100 最后 STDOUT 中按序輸出 1,2,3,4,5…100

題目要求用 Java 的 wait + notify 機制來實現,重點考察對于多線程可見性的理解。

wait 和 notify 簡介

wait 和 notify 均為 Object 的方法:

  • Object.wait() —— 暫停一個線程
  • Object.notify() —— 喚醒一個線程

從以上的定義中,我們可以了解到以下事實:

  • 想要使用這兩個方法,我們需要先有一個對象 Object。
  • 在多個線程之間,我們可以通過調用同一個對象的wait()和notify()來實現不同的線程間的可見。

對象控制權(monitor)

在使用 wait 和 notify 之前,我們需要先了解對象的控制權(monitor)。在 Java 中任何一個時刻,對象的控制權只能被一個線程擁有。如何理解控制權呢?請先看下面的簡單代碼:

public class Util {public void run(){Object ob = new Object();new Thread(new Runnable() {@Overridepublic void run() {try {ob.wait();} catch (InterruptedException e) {e.printStackTrace();}}}).start();} }

直接執行,我們將會得到以下異常:

E/AndroidRuntime: FATAL EXCEPTION: Thread-3Process: com.example.myapplication, PID: 12211java.lang.IllegalMonitorStateException: object not locked by thread before wait()at java.lang.Object.wait(Native Method)at java.lang.Object.wait(Object.java:442)at java.lang.Object.wait(Object.java:568)at com.example.myapplication.Util$1.run(Util.java:20)at java.lang.Thread.run(Thread.java:929)

出錯的代碼在:object.wait();。這里我們需要了解以下事實:

  • 無論是執行對象的 wait、notify 還是 notifyAll 方法,必須保證當前運行的線程取得了該對象的控制權(monitor)
  • 如果在沒有控制權的線程里執行對象的以上三種方法,就會報 java.lang.IllegalMonitorStateException 異常。
  • JVM 基于多線程,默認情況下不能保證運行時線程的時序性

在上面的示例代碼中,我們 new 了一個 Thread,但是對象 object 的控制權仍在主線程里。所以會報 java.lang.IllegalMonitorStateException 。

我們可以通過同步鎖來獲得對象控制權,例如:synchronized 代碼塊。對以上的示例代碼做改造:

public class Util {public void run(){Object ob = new Object();new Thread(new Runnable() {@Overridepublic void run() {synchronized (ob){try {ob.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}).start();} }

再次執行,代碼不再報錯。

我們可以得到以下結論:

  • 調用對象的wait()和notify()方法,需要先取得對象的控制權
  • 可以使用synchronized (object)來取得對于 object 對象的控制權

解題

了解了對象控制權之后,我們就可以正常地使用 notify 和 wait 了,下面給出我的解題方法,供參考。

方法一:

public class Util {public void run(){Object ob = new Object();new Thread(new Runnable() {@Overridepublic void run() {synchronized (ob){try {for (int i = 0 ;i < 100; i=i+2){ob.notify();Log.d("num--", "" + i); //偶數ob.wait();}} catch (InterruptedException e) {e.printStackTrace();}}}}).start();new Thread(new Runnable() {@Overridepublic void run() {synchronized (ob){try {for (int i = 1 ;i < 100; i=i+2){ob.notify();Log.d("num------", "" + i); //奇數ob.wait();}} catch (InterruptedException e) {e.printStackTrace();}}}}).start();} }

方法二:

public class Util {public void run(){Object ob = new Object();new Thread(new Runnable() {@Overridepublic void run() {synchronized (ob){try {for (int i = 0 ;i < 100; i=i+2){Log.d("num--", "" + i); //偶數ob.notifyAll();ob.wait();}} catch (InterruptedException e) {e.printStackTrace();}}}}).start();new Thread(new Runnable() {@Overridepublic void run() {synchronized (ob){try {for (int i = 1 ;i < 100; i=i+2){Log.d("num------", "" + i); //奇數ob.notifyAll();ob.wait();}} catch (InterruptedException e) {e.printStackTrace();}}}}).start();} }

發散:notify()和notifyAll()

這兩個方法均為 native 方法,在JDK 1.8 中的關于notify()的JavaDoc如下:

Wakes up a single thread that is waiting on this object’s monitor. If any threads are waiting on this object, one of them is chosen to be awakened.

譯為:

喚醒此 object 控制權下的一個處于 wait 狀態的線程。若有多個線程處于此 object 控制權下的 wait 狀態,只有一個會被喚醒。

也就是說,如果有多個線程在 wait 狀態,我們并不知道哪個線程會被喚醒。

在JDK 1.8 中的關于notifyAll()的JavaDoc如下:

Wakes up all threads that are waiting on this object’s monitor.

譯為:

喚醒所有處于此 object 控制權下的 wait 狀態的線程。

所以,我們需要根據實際的業務場景來考慮如何使用。

擴展

關于對象鎖,notify只是喚醒一個線程B,B這個線程要等到當前對象釋放synchronized的對象鎖才能執行,也就是A flag.wait()才能執行。再用高級點的說法,就是notify是等待池進入鎖池。

wait()方法 表示持有對象鎖的線程A準備釋放對象鎖權限,釋放CPU資源并進入等待。

Wait() 和notify() 方法只能從synchronized方法或塊中調用,需要在其他線程正在等待的對象上調用notify方法。

notifyAll 通知JVM喚醒所有競爭該對象鎖的線程,線程A synchronized 代碼作用域結束后,JVM通過算法將對象鎖權限指派給某個線程X,所有被喚醒的線程不再等待。線程X synchronized 代碼作用域結束后,之前所有被喚醒的線程都有可能獲得該對象鎖權限,這個由JVM算法決定。

通俗比喻:

有兩個人A和B都要和一個女孩G約會(A線程和B線程都調用synchronized約會方法,鎖對象G.class)。

A率先和G約會了(A線程進入synchronized方法),B只能等著。

A在約會途中被電話叫走,把G涼在那里(調用G.class.wait())。

這時候B發現G沒人約會了,于是上場(B線程進入synchronized方法)。

等到B和G約會完成,B又打電話叫A回來繼續約會(B線程調用G.class.notify()方法),A才回來繼續約會直到完成。

notifyAll()就是不止A和B了,可能有更多的人要和G約會,等A走了之后某個人上場。

總結

以上是生活随笔為你收集整理的JAVA多线程中wait()方法的详细分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。