JAVA wait(), notify(),sleep具體解釋

?
??? 在CSDN開了博客后,一直也沒在上面公布過文章,直到前一段時間與一位前輩的對話,才發現技術博客的重要,立志要把CSDN的博客建好。但一直沒有找到好的開篇的主題,今天再看JAVA線程相互排斥、同步的時候又有了新的體會,就以他作為開篇吧。

??? 在JAVA中,是沒有類似于PV操作、進程相互排斥等相關的方法的。JAVA的進程同步是通過synchronized()來實現的,須要說明的是,JAVA的synchronized()方法類似于操作系統概念中的相互排斥內存塊,在JAVA中的Object類型中,都是帶有一個內存鎖的,在有線程獲取該內存鎖后,其他線程無法訪問該內存,從而實現JAVA中簡單的同步、相互排斥操作。明確這個原理,就能理解為什么synchronized(this)與synchronized(static XXX)的差別了,synchronized就是針對內存區塊申請內存鎖,thiskeyword代表類的一個對象,所以其內存鎖是針對同樣對象的相互排斥操作,而static成員屬于類專有,其內存空間為該類全部成員共同擁有,這就導致synchronized()對static成員加鎖,相當于對類加鎖,也就是在該類的全部成員間實現相互排斥,在同一時間僅僅有一個線程可訪問該類的實例。假設僅僅是簡單的想要實如今JAVA中的線程相互排斥,明確這些基本就已經夠了。但假設須要在線程間相互喚醒的話就須要借助Object.wait(), Object.nofity()了。

??? Obj.wait(),與Obj.notify()必需要與synchronized(Obj)一起使用,也就是wait,與notify是針對已經獲取了Obj鎖進行操作,從語法角度來說就是Obj.wait(),Obj.notify必須在synchronized(Obj){...}語句塊內。從功能上來說wait就是說線程在獲取對象鎖后,主動釋放對象鎖,同一時候本線程休眠。直到有其他線程調用對象的notify()喚醒該線程,才干繼續獲取對象鎖,并繼續運行。對應的notify()就是對對象鎖的喚醒操作。但有一點需要注意的是notify()調用后,并非立即就釋放對象鎖的,而是在對應的synchronized(){}語句塊運行結束,自己主動釋放鎖后,JVM會在wait()對象鎖的線程中隨機選取一線程,賦予其對象鎖,喚醒線程,繼續運行。這樣就提供了在線程間同步、喚醒的操作。Thread.sleep()與Object.wait()二者都能夠暫停當前線程,釋放CPU控制權,基本的差別在于Object.wait()在釋放CPU同一時候,釋放了對象鎖的控制。

?

??? 單單在概念上理解清楚了還不夠,須要在實際的樣例中進行測試才干更好的理解。對Object.wait(),Object.notify()的應用最經典的樣例,應該是三線程打印ABC的問題了吧,這是一道比較經典的面試題,題目要求例如以下:

建立三個線程,A線程打印10次A,B線程打印10次B,C線程打印10次C,要求線程同一時候執行,交替打印10次ABC。這個問題用Object的wait(),notify()就能夠非常方便的解決。代碼例如以下:

?

?

public class MyThreadPrinter2 implements Runnable {   private String name;   private Object prev;   private Object self;   private MyThreadPrinter2(String name, Object prev, Object self) {   this.name = name;   this.prev = prev;   this.self = self;   }   @Override  public void run() {   int count = 10;   while (count > 0) {   synchronized (prev) {   synchronized (self) {   System.out.print(name);   count--;  self.notify();   }   try {   prev.wait();   } catch (InterruptedException e) {   e.printStackTrace();   }   }   }   }   public static void main(String[] args) throws Exception {   Object a = new Object();   Object b = new Object();   Object c = new Object();   MyThreadPrinter2 pa = new MyThreadPrinter2("A", c, a);   MyThreadPrinter2 pb = new MyThreadPrinter2("B", a, b);   MyThreadPrinter2 pc = new MyThreadPrinter2("C", b, c);   new Thread(pa).start();new Thread(pb).start();new Thread(pc).start();    }   
}  


?

???
??
???? 先來解釋一下其總體思路,從大的方向上來講,該問題為三線程間的同步喚醒操作,基本的目的就是ThreadA->ThreadB->ThreadC->ThreadA循環運行三個線程。為了控制線程運行的順序,那么就必需要確定喚醒、等待的順序,所以每個線程必須同一時候持有兩個對象鎖,才干繼續運行。一個對象鎖是prev,就是前一個線程所持有的對象鎖。另一個就是自身對象鎖。基本的思想就是,為了控制運行的順序,必需要先持有prev鎖,也就前一個線程要釋放自身對象鎖,再去申請自身對象鎖,兩者兼備時打印,之后首先調用self.notify()釋放自身對象鎖,喚醒下一個等待線程,再調用prev.wait()釋放prev對象鎖,終止當前線程,等待循環結束后再次被喚醒。運行上述代碼,能夠發現三個線程循環打印ABC,共10次。程序運行的主要過程就是A線程最先運行,持有C,A對象鎖,后釋放A,C鎖,喚醒B。線程B等待A鎖,再申請B鎖,后打印B,再釋放B,A鎖,喚醒C,線程C等待B鎖,再申請C鎖,后打印C,再釋放C,B鎖,喚醒A。看起來似乎沒什么問題,但假設你細致想一下,就會發現有問題,就是初始條件,三個線程依照A,B,C的順序來啟動,依照前面的思考,A喚醒B,B喚醒C,C再喚醒A。可是這樣的假設依賴于JVM中線程調度、運行的順序。詳細來說就是,在main主線程啟動ThreadA后,需要在ThreadA運行完,在prev.wait()等待時,再切回線程啟動ThreadB,ThreadB運行完,在prev.wait()等待時,再切回主線程,啟動ThreadC,僅僅有JVM依照這個線程運行順序運行,才干保證輸出的結果是正確的。而這依賴于JVM的詳細實現。考慮一種情況,例如以下:假設主線程在啟動A后,運行A,過程中又切回主線程,啟動了ThreadB,ThreadC,之后,因為A線程尚未釋放self.notify,也就是B需要在synchronized(prev)處等待,而這時C卻調用synchronized(prev)獲取了對b的對象鎖。這樣,在A調用完后,同一時候ThreadB獲取了prev也就是a的對象鎖,ThreadC的運行條件就已經滿足了,會打印C,之后釋放c,及b的對象鎖,這時ThreadB具備了運行條件,會打印B,也就是循環變成了ACBACB了。這樣的情況,能夠通過在run中主動釋放CPU,來進行模擬。代碼例如以下:

?

    public void run() {   int count = 10;   while (count > 0) {   synchronized (prev) {   synchronized (self) {   System.out.print(name);   count--;  try{Thread.sleep(1);}catch (InterruptedException e){e.printStackTrace();}self.notify();   }   try {   prev.wait();   } catch (InterruptedException e) {   e.printStackTrace();   }   }   }   }   


?


??? 執行后的打印結果就變成了ACBACB了。為了避免這樣的與JVM調度有關的不確定性。須要讓A,B,C三個線程以確定的順序啟動,終于代碼例如以下:

?

  
public class MyThreadPrinter2 implements Runnable {   private String name;   private Object prev;   private Object self;   private MyThreadPrinter2(String name, Object prev, Object self) {   this.name = name;   this.prev = prev;   this.self = self;   }   @Override  public void run() {   int count = 10;   while (count > 0) {   synchronized (prev) {   synchronized (self) {   System.out.print(name);   count--;  try{Thread.sleep(1);}catch (InterruptedException e){e.printStackTrace();}self.notify();   }   try {   prev.wait();   } catch (InterruptedException e) {   e.printStackTrace();   }   }   }   }   public static void main(String[] args) throws Exception {   Object a = new Object();   Object b = new Object();   Object c = new Object();   MyThreadPrinter2 pa = new MyThreadPrinter2("A", c, a);   MyThreadPrinter2 pb = new MyThreadPrinter2("B", a, b);   MyThreadPrinter2 pc = new MyThreadPrinter2("C", b, c);   new Thread(pa).start();Thread.sleep(10);new Thread(pb).start();Thread.sleep(10);new Thread(pc).start();Thread.sleep(10);}   
}  


?

?

?????? 這樣才干夠完美的解決該問題。通過這個樣例也是想說明一下,非常多理論、概念如Obj.wait(),Obj.notify()等,理解起來,比較簡單,可是在實際的應用其中,這里卻是往往出現故障的地方。須要更加深入的理解。并在解決這個問題的過程中不斷加深對概念的掌握。

?

????????????????????????????? ——歡迎轉載,請注明出處 http://blog.csdn.net/zyplus——

?

轉載于:https://www.cnblogs.com/zfyouxi/p/4516295.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/257274.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/257274.shtml
英文地址,請注明出處:http://en.pswp.cn/news/257274.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

通過鍵盤上下鍵 JS事件,控制候選詞的選擇項

效果圖 JS代碼 //上下鍵 選擇事件 searchBackgroud 為樣式,只做標記,無實質樣式,因為和其他樣式不兼容,只能添加CSS$(document).keydown(function (event) {var upDownClickNum $("#SearchTips .searchBackgroud ").l…

物理競賽得獎學計算機,物理競賽林紫琪帶你探索清華學堂計算機科學實驗班”(姚班)...

林紫琪,34屆全國中學生物理競賽全國第22名,獲得女生最高分,入選國家集訓隊,現就讀于清華姚班。這是一條小科普:“清華學堂計算機科學實驗班”(姚班)由世界著名計算機科學家姚期智院士于2005年創辦,致力于培…

Jmeter===Jmeter中使用CSV Data Set Config參數化不重復數據執行N遍(轉)

Jmeter中使用CSV Data Set Config參數化不重復數據執行N遍 要求: 今天要測試上千條數據,且每條數據要求執行多次,(模擬多用戶多次抽獎) 1.用戶id有175個,且沒有任何排序規則; 2.要求175個用戶都…

[轉]wireshark 實用過濾表達式(針對ip、協議、端口、長度和內容) 實例介紹

首先說幾個最常用的關鍵字,“eq” 和 “”等同,可以使用 “and” 表示并且,“or”表示或者。“!" 和 "not” 都表示取反。 一、針對wireshark最常用的自然是針對IP地址的過濾。其中有幾種情況: (1&#xff0…

[Flexbox] Using order to rearrange flexbox children

Using the order property we alter the order in which flexbox children appear on the page, without making changes to the dom. Desktop Mobile 轉載于:https://www.cnblogs.com/Answer1215/p/5453671.html

計算機怎么更改用戶頭像像,Win10系統電腦賬戶頭像怎么改成系統默認狀態?

為了保護電腦的安全,我們可以設置登錄賬號密碼,而賬號的頭像也是可以自行更換的。但是,某些時候,因為一些原因,我們需要將Win10系統賬戶的頭像去掉,即改成默認狀態。但是很多人都不清楚該怎么操作&#xff…

SPFA模板

今天去聽2015ZJOI浙江省隊第二試的集訓,早上就是聽得云里霧里的ORZ,下午某兩集訓隊大神過來將題目,第一個進了IOI的我只聽懂了10%ORZ,第二個人機交互很好玩,找個時間單獨寫下。 順便附帶膜拜各位聚聚,保我明…

LCM在Kernel中的代碼分析

lcm的分析首先是mtkfb.c 1.mtk_init中platform_driver_register(&mtkfb_driver)注冊平臺驅動 panelmaster_init(); DBG_init(); mtkfb_ipo_init(); 2.mtkfb_probe進行普配 3.然后執行primary_display_init(mtkfb_find_lcm_driver(),lcd_fps); 4.mtkfb_find_lcm_driver()進行…

html ascii編碼方式,HTML 字符集 參考手冊

要正確顯示一個 HTML 頁面,瀏覽器必須知道要使用的字符集(字符編碼)。HTML 字符集在 HTML 中,正確的字符編碼是什么?HTML5 中默認的字符編碼是 UTF-8。這并非總是如此。早期網絡的字符編碼是 ASCII 碼。后來,從 HTML 2.0 到 HTML …

JavaScript 中的閉包和作用域鏈(讀書筆記)

要想理解閉包,應當先理解JavaScript的作用域和作用域鏈。 JavaScript有一個特性被稱之為“聲明提前(hoisting)”,即JavaScript函數里聲明的所有變量(但不涉及賦值)都被“提前”至函數體的頂部,“…

leetcode jump game ii

題目: Given an array of non-negative integers, you are initially positioned at the first index of the array. Each element in the array represents your maximum jump length at that position. Your goal is to reach the last index in the minimum numb…

韓師師范學院計算機科學與技術在哪個學區,2017年韓山師范學院本科插班生考試《數據結構》A卷...

韓山師范學院2017年本科插班生考試試卷計算機科學與技術 專業 數據結構 試卷(A 卷)一、單項選擇題(每題2分,共30分)1. 對線性表,在下列哪種情況下應當采用鏈表表示?( ) A. 經常需要隨機地存取元素 B. 經常需要進行插入和刪除操作 C. 表中元素…

JAVA取隨機數,石頭剪刀布實例

一、取隨機數: import java.util.Random; //導入隨機數 public class Test{public static void main(String[] args){Random xx new Random(); //聲明隨機數int number xx.nextInt(10); //賦值隨機數給numberSystem.out.println("隨機數…

計算機網絡犯罪和一般犯罪的不同,論計算機網絡犯罪題稿.doc

目 錄摘要2第一章、網絡犯罪概念、特點以及構成特征5(一)網絡犯罪的概念認定5(二)網絡犯罪的特點6(三)網絡犯罪的構成7第二章、?網絡犯罪的類型9(一)網絡色情和性騷擾9(二)欺詐9(三)販賣、銷售違禁物品11(四)妨害名譽、侵犯個人隱私12(五)?制造、傳播計算機病毒12第三章、?網…

實例變量和靜態變量(或類變量static)

一個類通過使用運算符new可以創建多個不同的對象,這些對象將被分配不同的內存空間,準確的說法是:不同對象的實例變量將被分配不同的內存空間,如果類中有類變量,那么所有對象的這個類變量都被分配到同一處內存&#xff…

DB2 數據庫清表語句

truncate table DWDM2.tablename IMMEDIATE; alter table DWDM1.tablename activate not logged initially with empty table; but which one is best ? the truncate should be better 轉載于:https://www.cnblogs.com/TendToBigData/p/10501485.html

cnblogs_504 Gateway Time-out

地址:http://zzk.cnblogs.com/s?tb&w%E6%B1%82%E8%81%8C 504 Gateway Time-out 504 Gateway Time-out The gateway did not receive a timely response from the upstream server or application. Sorry for the inconvenience. Please report this message an…

第一階段

初步實現了相機的調用,做了簡單界面,并沒有實現核心功能 Button button (Button) findViewById(R.id.sao);button.setOnClickListener(new OnClickListener(){Overridepublic void onClick(View v) {Intent intent new Intent(MediaStore.ACTION_IMAGE…

JavaScript 詳說事件機制之冒泡、捕獲、傳播、委托

DOM事件流(event flow )存在三個階段:事件捕獲階段、處于目標階段、事件冒泡階段。 事件捕獲(event capturing):通俗的理解就是,當鼠標點擊或者觸發dom事件時,瀏覽器會從根節點開始…

很棒的HTML5效果實例

2019獨角獸企業重金招聘Python工程師標準>>> http://mrdoob.com/141/Internet_Explorer_with_WebGL 轉載于:https://my.oschina.net/u/3647620/blog/1552495