Java同步異步相關(guān)知識(shí)點(diǎn)_第1頁
Java同步異步相關(guān)知識(shí)點(diǎn)_第2頁
Java同步異步相關(guān)知識(shí)點(diǎn)_第3頁
Java同步異步相關(guān)知識(shí)點(diǎn)_第4頁
Java同步異步相關(guān)知識(shí)點(diǎn)_第5頁
已閱讀5頁,還剩7頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、Java同步、異步相關(guān)知識(shí)點(diǎn)關(guān)鍵字: java同步、異步相關(guān)知識(shí)點(diǎn)一、關(guān)鍵字:thread(線程)、thread-safe(線程安全)、intercurrent(并發(fā)的)synchronized(同步的)、asynchronized(異步的)、volatile(易變的)、atomic(原子的)、share(共享)二、總結(jié)背景:一次讀寫共享文件編寫,嚯,好家伙,竟然揪出這些零碎而又是一路的知識(shí)點(diǎn)。于是乎,Google和翻閱了Java參考大全、Effective Java Second Edition,特此總結(jié)一下供日后工作學(xué)習(xí)參考。三、概念:1、 什么時(shí)候必須同步?什么叫同步?如何同步? 要跨線

2、程維護(hù)正確的可見性,只要在幾個(gè)線程之間共享非 final 變量,就必須使用 synchronized(或 volatile)以確保一個(gè)線程可以看見另一個(gè)線程做的更改。為了在線程之間進(jìn)行可靠的通信,也為了互斥訪問,同步是必須的。這歸因于java語言規(guī)范的內(nèi)存模型,它規(guī)定了:一個(gè)線程所做的變化何時(shí)以及如何變成對(duì)其它線程可見。因?yàn)槎嗑€程將異步行為引進(jìn)程序,所以在需要同步時(shí),必須有一種方法強(qiáng)制進(jìn)行。例如:如果2個(gè)線程想要通信并且要共享一個(gè)復(fù)雜的數(shù)據(jù)結(jié)構(gòu),如鏈表,此時(shí)需要確保它們互不沖突,也就是必須阻止B線程在A線程讀數(shù)據(jù)的過程中向鏈表里面寫數(shù)據(jù)(A獲得了鎖,B必須等A釋放了該鎖)。為了達(dá)到這個(gè)目的,j

3、ava在一個(gè)舊的的進(jìn)程同步模型監(jiān)控器(Monitor)的基礎(chǔ)上實(shí)現(xiàn)了一個(gè)巧妙的方案:監(jiān)控器是一個(gè)控制機(jī)制,可以認(rèn)為是一個(gè)很小的、只能容納一個(gè)線程的盒子,一旦一個(gè)線程進(jìn)入監(jiān)控器,其它的線程必須等待,直到那個(gè)線程退出監(jiān)控為止。通過這種方式,一個(gè)監(jiān)控器可以保證共享資源在同一時(shí)刻只可被一個(gè)線程使用。這種方式稱之為同步。(一旦一個(gè)線程進(jìn)入一個(gè)實(shí)例的任何同步方法,別的線程將不能進(jìn)入該同一實(shí)例的其它同步方法,但是該實(shí)例的非同步方法仍然能夠被調(diào)用)。錯(cuò)誤的理解:同步嘛,就是幾個(gè)線程可以同時(shí)進(jìn)行訪問。同步和多線程關(guān)系:沒多線程環(huán)境就不需要同步;有多線程環(huán)境也不一定需要同步。鎖提供了兩種主要特性:互斥(mutua

4、l exclusion) 和可見性(visibility)。互斥即一次只允許一個(gè)線程持有某個(gè)特定的鎖,因此可使用該特性實(shí)現(xiàn)對(duì)共享數(shù)據(jù)的協(xié)調(diào)訪問協(xié)議,這樣,一次就只有一個(gè)線程能夠使用該共享數(shù)據(jù)??梢娦砸訌?fù)雜一些,它必須確保釋放鎖之前對(duì)共享數(shù)據(jù)做出的更改對(duì)于隨后獲得該鎖的另一個(gè)線程是可見的 如果沒有同步機(jī)制提供的這種可見性保證,線程看到的共享變量可能是修改前的值或不一致的值,這將引發(fā)許多嚴(yán)重問題小結(jié):為了防止多個(gè)線程并發(fā)對(duì)同一數(shù)據(jù)的修改,所以需要同步,否則會(huì)造成數(shù)據(jù)不一致(就是所謂的:線程安全。如java集合框架中 Hashtable和Vector是線程安全的。我們的大部分程序都不是線程安全的

5、,因?yàn)闆]有進(jìn)行同步,而且我們沒有必要,因?yàn)榇蟛糠智闆r根本沒有多線程環(huán)境)。2、 什么叫原子的(原子操作)? Java原子操作是指:不會(huì)被打斷地的操作。(就是做到互斥 和可見性??。┠请y道原子操作就可以真的達(dá)到線程安全同步效果了嗎?實(shí)際上有一些原子操作不一定是線程安全的。那么,原子操作在什么情況下不是線程安全的呢?也許是這個(gè)原因?qū)е碌模簀ava線程允許線程在自己的內(nèi)存區(qū)保存變量的副本。允許線程使用本地的私有拷貝進(jìn)行工作而非每次都使用主存的值是為了提高性能(本人愚見:雖然原子操作是線程安全的,可各線程在得到變量(讀操作)后,就是各自玩弄自己的副本了,更新操作(寫操作)因未寫入主存中,導(dǎo)致其它線程不

6、可見)。那該如何解決呢?因此需要通過java同步機(jī)制。 在java中,32位或者更少位數(shù)的賦值是原子的。在一個(gè)32位的硬件平臺(tái)上,除了double和long型的其它原始類型通常都是使用32位進(jìn)行表示,而double和long通常使用64位表示。另外,對(duì)象引用使用本機(jī)指針實(shí)現(xiàn),通常也是32位的。對(duì)這些32位的類型的操作是原子的。 這些原始類型通常使用32位或者64位表示,這又引入了另一個(gè)小小的神話:原始類型的大小是由語言保證的。這是不對(duì)的。java語言保證的是原始類型的表數(shù)范圍而非JVM中的存儲(chǔ)大小。因此,int型總是有相同的表數(shù)范圍。在一個(gè)JVM上可能使用32位實(shí)現(xiàn),而在另一個(gè)JVM上可能是6

7、4位的。在此再次強(qiáng)調(diào):在所有平臺(tái)上被保證的是表數(shù)范圍,32位以及更小的值的操作是原子的。 3、 不要搞混了:同步、異步舉個(gè)例子:普通B/S模式(同步)AJAX技術(shù)(異步)同步:提交請(qǐng)求->等待服務(wù)器處理->處理完返回 這個(gè)期間客戶端瀏覽器不能干任何事異步:請(qǐng)求通過事件觸發(fā)->服務(wù)器處理(這是瀏覽器仍然可以作其他事情)->處理完畢可見,彼“同步”非此“同步”我們說的java中的那個(gè)共享數(shù)據(jù)同步(synchronized)一個(gè)同步的對(duì)象是指行為(動(dòng)作),一個(gè)是同步的對(duì)象是指物質(zhì)(共享數(shù)據(jù))。4、 Java同步機(jī)制有4種實(shí)現(xiàn)方式:(部分引用網(wǎng)上資源) ThreadLocal

8、synchronized( ) wait() 與 notify() volatile目的:都是為了解決多線程中的對(duì)同一變量的訪問沖突ThreadLocal ThreadLocal 保證不同線程擁有不同實(shí)例,相同線程一定擁有相同的實(shí)例,即為每一個(gè)使用該變量的線程提供一個(gè)該變量值的副本,每一個(gè)線程都可以獨(dú)立改變自己的副本,而不是與其它線程的副本沖突。優(yōu)勢:提供了線程安全的共享對(duì)象與其它同步機(jī)制的區(qū)別:同步機(jī)制是為了同步多個(gè)線程對(duì)相同資源的并發(fā)訪問,是為了多個(gè)線程之間進(jìn)行通信;而 ThreadLocal 是隔離多個(gè)線程的數(shù)據(jù)共享,從根本上就不在多個(gè)線程之間共享資源,這樣當(dāng)然不需要多個(gè)線程進(jìn)行同步了。

9、volatile volatile 修飾的成員變量在每次被線程訪問時(shí),都強(qiáng)迫從共享內(nèi)存中重讀該成員變量的值。而且,當(dāng)成員變量發(fā)生變化時(shí),強(qiáng)迫線程將變化值回寫到共享內(nèi)存。 優(yōu)勢:這樣在任何時(shí)刻,兩個(gè)不同的線程總是看到某個(gè)成員變量的同一個(gè)值。 緣由:Java 語言規(guī)范中指出,為了獲得最佳速度,允許線程保存共享成員變量的私有拷貝,而且只當(dāng)線程進(jìn)入或者離開同步代碼塊時(shí)才與共享成員變量的原始值對(duì)比。這樣當(dāng)多個(gè)線程同時(shí)與某個(gè)對(duì)象交互時(shí),就必須要注意到要讓線程及時(shí)的得到共享成員變量的變化。而 volatile 關(guān)鍵字就是提示 VM :對(duì)于這個(gè)成員變量不能保存它的私有拷貝,而應(yīng)直接與共享成員變量交互。 使用技

10、巧:在兩個(gè)或者更多的線程訪問的成員變量上使用 volatile 。當(dāng)要訪問的變量已在 synchronized 代碼塊中,或者為常量時(shí),不必使用。 線程為了提高效率,將某成員變量(如A)拷貝了一份(如B),線程中對(duì)A的訪問其實(shí)訪問的是B。只在某些動(dòng)作時(shí)才進(jìn)行A和B的同步,因此存在A和B不一致的情況。volatile就是用來避免這種情況的。 volatile告訴jvm,它所修飾的變量不保留拷貝,直接訪問主內(nèi)存中的(讀操作多時(shí)使用較好;線程間需要通信,本條做不到) Volatile 變量具有 synchronized 的可見性特性,但是不具備原子特性。這就是說線程能夠自動(dòng)發(fā)現(xiàn) volatile 變

11、量的最新值。Volatile 變量可用于提供線程安全,但是只能應(yīng)用于非常有限的一組用例:多個(gè)變量之間或者某個(gè)變量的當(dāng)前值與修改后值之間沒有約束。 您只能在有限的一些情形下使用 volatile 變量替代鎖。要使 volatile 變量提供理想的線程安全,必須同時(shí)滿足下面兩個(gè)條件:對(duì)變量的寫操作不依賴于當(dāng)前值;該變量沒有包含在具有其他變量的不變式中。sleep() vs wait() sleep是線程類(Thread)的方法,導(dǎo)致此線程暫停執(zhí)行指定時(shí)間,把執(zhí)行機(jī)會(huì)給其他線程,但是監(jiān)控狀態(tài)依然保持,到時(shí)后會(huì)自動(dòng)恢復(fù)。調(diào)用 sleep不會(huì)釋放對(duì)象鎖。 wait是Object類的方法,對(duì)此對(duì)象調(diào)用wa

12、it方法導(dǎo)致本線程放棄對(duì)象鎖,進(jìn)入等待此對(duì)象的等待鎖定池,只有針對(duì)此對(duì)象發(fā)出notify方法(或 notifyAll)后本線程才進(jìn)入對(duì)象鎖定池準(zhǔn)備獲得對(duì)象鎖進(jìn)入運(yùn)行狀態(tài)。(如果變量被聲明為volatile,在每次訪問時(shí)都會(huì)和主存一致;如果變量在同步方法或者同步塊中被訪問,當(dāng)在方法或者塊的入口處獲得鎖以及方法或者塊退出時(shí)釋放鎖時(shí)變量被同步。)四、例子:Demo1:package test.thread;/* author ydj*/class SynTest /非同步 static void method(Thread thread) try Thread.sleep(2000); catch(

13、Exception ex) ex.printStackTrace(); /同步方式一:同步方法 synchronized static void method1(Thread thread)/這個(gè)方法是同步的方法,每次只有一個(gè)線程可以進(jìn)來 try Thread.sleep(2000); catch(Exception ex) ex.printStackTrace(); /同步方式二:同步代碼塊 static void method2(Thread thread) synchronized(SynTest.class) try Thread.sleep(2000); catch(Exceptio

14、n ex) ex.printStackTrace(); /同步方式三:使用同步對(duì)象鎖 private static Object _lock1=new Object(); private static byte _lock2=;/據(jù)說,此鎖更可提高性能。源于:鎖的對(duì)象越小越好 static void method3(Thread thread) synchronized(_lock1) try Thread.sleep(2000); catch(Exception ex) ex.printStackTrace(); public static void main(String args) /啟

15、動(dòng)3個(gè)線程,這里用了匿名類 for(int i=0;i<3;i+) new Thread() public void run() method(this); /method1(this); /method2(this); /method3(this); .start(); /* 執(zhí)行method()方法結(jié)果: begin Thread-0 begin Thread-2 begin Thread-1 end Thread-1 end Thread-0 end Thread-2 說明了:在沒有同步限制的條件下,多個(gè)線程可以同時(shí)進(jìn)入一個(gè)對(duì)象的方法中操作。 這樣對(duì)共享可變數(shù)據(jù)是不安全的,即常說的

16、:非線程安全(non thread-safe)。*/* 執(zhí)行method1()/method2()/method3()方法結(jié)果(可能線程進(jìn)入的順序不同): begin Thread-0 end Thread-0 begin Thread-1 end Thread-1 begin Thread-2 end Thread-2 說明了:在同步限制的條件下,同時(shí)只可有一個(gè)線程進(jìn)入一個(gè)對(duì)象的方法中操作,其它線程必須等待先它的線程退出后才可進(jìn)入。 這樣可保證共享可變數(shù)據(jù)是安全的,即常說的:線程安全(thread-safe )。*/Demo2:package test.thread;/* author yd

17、j*/public class SynTest2 public static void main(String args) Callme target=new Callme(); Caller ob1=new Caller(target,"Hello"); Caller ob2=new Caller(target,"Synchronized"); Caller ob3=new Caller(target,"World"); class Callme /* * 有和沒有synchronized的時(shí)候,結(jié)果是不一樣的 */ synchro

18、nized void test() LogUtil.log("測試是否是:一旦一個(gè)線程進(jìn)入一個(gè)實(shí)例的任何同步方法,別的線程將不能進(jìn)入該同一實(shí)例的其它同步方法,但是該實(shí)例的非同步方法仍然能夠被調(diào)用"); void nonsynCall(String msg) LogUtil.log(""+msg); LogUtil.log(""); synchronized void synCall(String msg) LogUtil.logPrint(""+msg); LogUtil.log(""); class Caller implements Runnable String msg; Callme target; Thread t; Caller(Callme t

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論