線程同步以及yield()、wait()、Notify()、Notifyall()

一、線程同步

1、線程同步的目的是為了保護多個線程訪問一個資源時對資源的破壞。
2、線程同步方法是通過鎖來實現,每個對象都有切僅有一個鎖,這個鎖與一個特定的對象關聯,線程一旦獲取了對象鎖,其他訪問該對象的線程就無法再訪問該對象的其他同步方法。
二、實現同步機制的兩個方法
1。同步代碼塊:?
synchronized(同一個數據){} 同一個數據:就是N條線程同時訪問一個數據。?
2。?
同步方法:?
public synchronized 數據返回類型 方法名(){}?
就是使用 synchronized 來修飾某個方法,則該方法稱為同步方法。對于同步方法而言,無需顯示指定同步監視器,同步方法的同步監視器是 this 也就是該對象的本身(這里指的對象本身有點含糊,其實就是調用該同步方法的對象)通過使用同步方法,可非常方便的將某類變成線程安全的類,具有如下特征:?
1,該類的對象可以被多個線程安全的訪問。?
2,每個線程調用該對象的任意方法之后,都將得到正確的結果。?
3,每個線程調用該對象的任意方法之后,該對象狀態依然保持合理狀態。?
注:synchronized關鍵字可以修飾方法,也可以修飾代碼塊,但不能修飾構造器,屬性等。?
實現同步機制注意以下幾點: 安全性高,性能低,在多線程用。性能高,安全性低,在單線程用。?
關鍵代碼如下:
編寫打印機類:Printer ?定義兩個方法
package cn.d.happy;public class Printer {Object o=new Object();//或在void前加synchronizedpublic void print1(){//同步代碼塊synchronized (o){System.out.print("線");System.out.print("程");System.out.print("同");System.out.print("步");System.out.println();}}public void print2(){synchronized (o){System.out.print("噢");System.out.print("呵");System.out.println();}}
}

定義兩個線程類 并重寫run方法。繼承Thread 和 實現Runnable接口 通過for循環遍歷次數

package cn.d.happy;public class MyThread extends Thread{public Printer print;@Override
public void run() {//必須有該類的對象實例for (int i = 1; i <=10; i++) {print.print1();}
}
}
package cn.d.happy;public class MyThread2 implements Runnable{public  Printer print;@Overridepublic void run() {for (int i = 1; i <=10; i++) {print.print2();}}}

測試類 創建打印機對象 ?以及兩個線程對象并進行賦值

package cn.d.happy;public class Test {
public static void main(String[] args) {//購買一個打印機Printer p=new Printer();//創建第一個線程對象  并且給屬性賦值MyThread t1=new MyThread();t1.print=p;t1.start();//03.創建第二個線程對象 并且給屬性賦值MyThread2 t2=new MyThread2();t2.print=p;Thread tt=new Thread(t2);tt.start();
}
}

實現效果:


?

三、Java多線程之yield()、wait()、Notify()、Notifyall()

yield()、

1)????通過yield?()函數,可使線程進入可執行狀態,排程器從可執行狀態的線程中重新進行排程。所以調用了yield()的函數也有可能馬上被執行。
2)????當調用yield?()函數后,線程不會釋放它的“鎖標志”。

class TestThreadMethod extends Thread{public static int shareVar = 0;public TestThreadMethod(String name){super(name);}public synchronized void run(){for(int i=0; i<4; i++){System.out.print(Thread.currentThread().getName());System.out.println(" : " + i);Thread.yield();}}}public class TestThread{public static void main(String[] args){TestThreadMethod t1 = new TestThreadMethod("t1");TestThreadMethod t2 = new TestThreadMethod("t2");t1.start();t1.start(); //(1)//t2.start(); (2)}

運行結果為:
t1?:?0
t1?:?1
t1?:?2
t1?:?3
t1?:?0
t1?:?1
t1?:?2
t1?:?3
從結果可知調用yield()時并不會釋放對象的“鎖標志”。
如果把代碼(1)注釋掉,并去掉代碼(2)的注釋,結果為:
t1?:?0
t1?:?1
t2?:?0
t1?:?2
t2?:?1
t1?:?3
t2?:?2
t2?:?3
從結果可知,雖然t1線程調用了yield(),但它馬上又被執行了。?

?wait與notify是java同步機制中重要的組成部分。結合與synchronized關鍵字使用,可以建立很多優秀的同步模型。
?synchronized(this){ }等價于publicsynchronized void method(){.....}
?同步分為類級別和對象級別,分別對應著類鎖和對象鎖。類鎖是每個類只有一個,如果static的方法被synchronized關鍵字修飾,則在這個方法被執行前必須獲得類鎖;對象鎖類同。
???首先,調用一個Object的wait與notify/notifyAll的時候,必須保證調用代碼對該Object是同步的,也就是說必須在作用等同于synchronized(obj){......}的內部才能夠去調用obj的wait與notify/notifyAll三個方法,否則就會報錯:
??java.lang.IllegalMonitorStateException:current thread not owner
??在調用wait的時候,線程自動釋放其占有的對象鎖,同時不會去申請對象鎖。當線程被喚醒的時候,它才再次獲得了去獲得對象鎖的權利。
??所以,notify與notifyAll沒有太多的區別,只是notify僅喚醒一個線程并允許它去獲得鎖,notifyAll是喚醒所有等待這個對象的線程并允許它們去獲得對象鎖,只要是在synchronied塊中的代碼,沒有對象鎖是寸步難行的。其實喚醒一個線程就是重新允許這個線程去獲得對象鎖并向下運行。

???notifyAll,雖然是對每個wait的對象都調用一次notify,但是這個還是有順序的,每個對象都保存這一個等待對象鏈,調用的順序就是這個鏈的順序。其實啟動等待對象鏈中各個線程的也是一個線程,在具體應用的時候,需要注意一下。

??wait(),notify(),notifyAll()不屬于Thread類,而是屬于Object基礎類,也就是說每個對像都有wait(),notify(),notifyAll()的功能。因為都個對像都有鎖,鎖是每個對像的基礎,當然操作鎖的方法也是最基礎了。

wait():

等待對象的同步鎖,需要獲得該對象的同步鎖才可以調用這個方法,否則編譯可以通過,但運行時會收到一個異常:IllegalMonitorStateException。

調用任意對象的 wait() 方法導致該線程阻塞,該線程不可繼續執行,并且該對象上的鎖被釋放。

notify():

喚醒在等待該對象同步鎖的線程(只喚醒一個,如果有多個在等待),注意的是在調用此方法的時候,并不能確切的喚醒某一個等待狀態的線程,而是由JVM確定喚醒哪個線程,而且不是按優先級。

調用任意對象的notify()方法則導致因調用該對象的 wait()方法而阻塞的線程中隨機選擇的一個解除阻塞(但要等到獲得鎖后才真正可執行)。

notifyAll():

喚醒所有等待的線程,注意喚醒的是notify之前wait的線程,對于notify之后的wait線程是沒有效果的。

?

通常,多線程之間需要協調工作:如果條件不滿足,則等待;當條件滿足時,等待該條件的線程將被喚醒。在Java中,這個機制的實現依賴于wait/notify。等待機制與鎖機制是密切關聯的。

例如:

?

synchronized(obj) {while(!condition) {obj.wait();}obj.doSomething();}

?

當線程A獲得了obj鎖后,發現條件condition不滿足,無法繼續下一處理,于是線程A就wait()。
在另一線程B中,如果B更改了某些條件,使得線程A的condition條件滿足了,就可以喚醒線程A :

synchronized(obj) {condition = true;obj.notify();}

synchronized和wait()、notify()等的關系:?

1.有synchronized的地方不一定有wait,notify

2.有wait,notify的地方必有synchronized.這是因為wait和notify不是屬于線程類,而是每一個對象都具有的方法,而且,這兩個方法都和對象鎖有關,有鎖的地方,必有synchronized。

另外,注意一點:如果要把notify和wait方法放在一起用的話,必須先調用notify后調用wait,因為如果調用完wait,該線程就已經不是currentthread了。

?

?

?

?

?

轉載于:https://www.cnblogs.com/WJ-163/p/5770304.html

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

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

相關文章

面試:整理面試中常被問到的8種數據結構

數據結構是一種特殊的組織和存儲數據的方式&#xff0c;可以使我們可以更高效地對存儲的數據執行操作。數據結構在計算機科學和軟件工程領域具有廣泛而多樣的用途。幾乎所有已開發的程序或軟件系統都使用數據結構。此外&#xff0c;數據結構屬于計算機科學和軟件工程的基礎。當…

python繪制繁花曲線代碼_使用python和pygame繪制繁花曲線的方法

前段時間看了一期《最強大腦》&#xff0c;里面各種繁花曲線組合成了非常美麗的圖形&#xff0c;一時心血來潮&#xff0c;想嘗試自己用代碼繪制繁花曲線&#xff0c;想怎么組合就怎么組合。真實的繁花曲線使用一種稱為繁花曲線規的小玩意繪制&#xff0c;繁花曲線規由相互契合…

Axure原型制作規范

一、 名詞定義&#xff1a; Sitemap 導航圖Widgets 組件Master 庫Label 控件名Interactions 交互動作Annotations 注釋Location and size 位置和尺寸二、 Widgets規范 本站常用widgets規范&#xff1a;命名規范&#xff1a;制定命名規范從而方便搜索和升級。 a. 全站使用&#…

系統測試相關知識筆記

1、系統測試的意義系統測試是為了發現系統中的錯誤而執行程序的過程&#xff0c;發現系統中存在的問題&#xff0c;及時處理掉&#xff0c;從而規避項目后續階段順利推進的風險、和高質量的軟件交付給客戶。2、系統測試的目的希望以最少的人力和時間發現潛在的各種錯誤和缺陷。…

最小生成樹練習1(克魯斯卡爾算法Kruskal)

今天刷一下水題練手入門&#xff0c;明天繼續。 poj1861 Network&#xff08;最小生成樹&#xff09;新手入門題。 題意&#xff1a;輸出連接方案中最長的單根網線長度&#xff08;必須使這個值是所有方案中最小的&#xff09;&#xff0c;然后輸出方案。 題解&#xff1a;本題…

java變量不聲明可以直接使用嗎_我們可以在不使用Java進行初始化的情況下聲明最終變量嗎?...

在Java中&#xff0c;final是可與字段類和方法一起使用的access修飾符。當一個方法為final時&#xff0c;它不能被覆蓋。當變量為最終變量時&#xff0c;其值無法進一步修改。當類結束時&#xff0c;不能擴展。無需初始化即可聲明最終變量如果稍后聲明了最終變量&#xff0c;則…

系統測試:單元測試相關知識筆記

一、單元測試概念單元測試也成為模塊測試&#xff0c;在模塊編寫完成且無編譯錯誤后就可以進行。單元測試側重模塊中的內部處理邏輯和數據結構。如果采用機器測試&#xff0c;一般用白盒測試法。二、單元測試檢查模塊特征1、模塊接口模塊接口保證了測試模塊數據流可以正確地流入…

跨網段遠程調試vs_如何提高后臺服務應用問題的排查效率?日志 VS 遠程調試

轉眼間&#xff0c;距離Jerry最近一篇文章推送已經過去了一個多月的時間了。公眾號更新的頻率降低&#xff0c;不是因為Jerry偷懶&#xff0c;而是由于從春節過后&#xff0c;我所在的SAP成都研究院數字創新空間整個團隊&#xff0c;一直在忙一個5月份需要交付的項目上。Jerry每…

計算機硬件知識:BIOS、EFI與UEFI詳解!

本文估計很多小白看不懂&#xff0c;但是還是建議你硬著頭皮看完&#xff0c;這篇文章主要講解了這幾種“BIOS”的啟動方式&#xff0c;對電腦啟動問題判斷的理解會有益處。BIOS是個程序&#xff0c;存儲在BIOS芯片中&#xff0c;而現在的新式電腦用的基本都是UEFI啟動&#xf…

java pdf 導出下載_Java+PDF模板導出成pdf文件,并下載

1&#xff0c;根據前人經驗&#xff0c;熟悉完成基礎操作&#xff1a;https://www.cnblogs.com/wangpeng00700/p/8418594.html?tdsourcetags_pcqq_aiomsg2&#xff0c;根據鏈接中操作完成之后&#xff0c;在本地生成pdf文件已經沒有問題了。但如果放到&#xff0c;Linux服務器…

在db2數據庫上模擬死鎖場景 還是z上的

如果條件允許&#xff0c;起兩個線程互相搶資源就行了&#xff0c;但問題是&#xff0c;時間上還需要同步&#xff0c;要做到完美控制&#xff0c;還得加其他邏輯&#xff0c;忒費事&#xff0c;所以可以用下面的辦法&#xff1a; 在目標表上直接加個鎖……簡單&#xff0c;粗暴…

條件隨機場 python_用條件隨機場做網絡小說命名實體識別

一直想用統計學習方法來改善撥云搜索&#xff0c;這次先在命名實體上小小嘗試一下。線性鏈條件隨機場對于無向圖中的節點&#xff0c;定義一組特征函數&#xff0c;使其狀態僅受鄰近節點和觀測序列的影響。在標注任務中&#xff0c;節點只有前后兩個鄰近節點&#xff0c;即線性…

項目開發基礎:常用測試方法介紹

1、集成測試集成測試就是把模塊按照設計說明書的要求組合起來進行測試。1.1、集成測試方法&#xff1a;a、分別測試各個模塊&#xff0c;再把這些模塊組合起來進行整體測試&#xff0c;也就是非增量式集成。特點&#xff1a;可以對模塊進行并行測試&#xff0c;能充分利用人力&…

java 多數據源處理_java – 用于處理多個數據源的Spring事務管理

這可能是一個重復的問題,但我找不到(至少我無法理解)一個滿意的答案,因此再次提問.我正在使用兩個數據源(MySQL和Oracle).以下是執行流程&#xff1a;主方法-A調用方法-B(寫入Oracle DB)然后它(方法-A)調用方法-C(寫入mySQL DB)然后它(方法-A)調用方法-D(寫入Oracle DB) ).如果…

MyBatis Generator

1 <?xml version"1.0" encoding"UTF-8"?>2 <!DOCTYPE generatorConfiguration3 PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"4 "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"&g…

svd奇異值分解_NCL專輯 | 奇異值分解(SVD)

奇異值分解SVD(Singular Value Decomposition)是一種矩陣分解方法&#xff0c;在氣象領域中常用來分析兩個氣象場場之間的關系。NCL的函數庫中與SVD相關的函數包括svd_lapack&#xff0c;svdcov&#xff0c;svdcov_sv&#xff0c;svdstd&#xff0c;svdstd_sv。svd_lapack&…