Java多線程并發(fā)編程知識(shí)點(diǎn)總結(jié)_第1頁(yè)
Java多線程并發(fā)編程知識(shí)點(diǎn)總結(jié)_第2頁(yè)
Java多線程并發(fā)編程知識(shí)點(diǎn)總結(jié)_第3頁(yè)
Java多線程并發(fā)編程知識(shí)點(diǎn)總結(jié)_第4頁(yè)
Java多線程并發(fā)編程知識(shí)點(diǎn)總結(jié)_第5頁(yè)
已閱讀5頁(yè),還剩5頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、1、線程的狀態(tài)1.1創(chuàng)建 線程 的兩種方式,接口和線程類。利用接口的好處:更好的體現(xiàn)面向?qū)ο蟮乃枷?,可以避免由于Java的單繼承特性而帶來(lái)的局限;增強(qiáng)程序的健壯性,代碼能夠被多個(gè)線程共享,代碼與數(shù)據(jù)是獨(dú)立的;(同步問(wèn)題)適合多個(gè)相同程序代碼的線程區(qū)處理同一資源的情況。(關(guān)注微信訂閱號(hào):javaedu)1.2線程就緒等待調(diào)度運(yùn)行start()方法。1.3線程的中斷這里需要注意的是,如果只是單純的調(diào)用interrupt()方法,線程并沒(méi)有實(shí)際被中斷,會(huì)繼續(xù)往下執(zhí)行。1.4、線程掛起和恢復(fù)(掛起還擁有對(duì)象鎖,死鎖)線程的掛起和恢復(fù)實(shí)現(xiàn)的正確方法是:通過(guò)設(shè)置標(biāo)志位,讓線程在安全的位置掛起1.5 利用多

2、線程模擬同步運(yùn)行用jion方法,mThread.jion()表示該線程運(yùn)行完畢后,在運(yùn)行調(diào)用它的線程。1.6 sleep 休眠當(dāng)線程執(zhí)行Thread.sleep()時(shí),它一直阻塞到指定的毫秒時(shí)間之后,或者阻塞被另一個(gè)線程打斷;1.7stop線程停止stop方法突然終止線程(持有這些鎖必定有某種合適的理由也許是阻止其他線程訪問(wèn)尚未處于一致性狀態(tài)的數(shù)據(jù),突然釋放鎖可能使某些對(duì)象中的數(shù)據(jù)處于不一致?tīng)顟B(tài))1.8線程可以阻塞于四種狀態(tài):(參考資料:當(dāng)線程執(zhí)行Thread.sleep()時(shí),它一直阻塞到指定的毫秒時(shí)間之后,或者阻塞被另一個(gè)線程打斷;當(dāng)線程碰到一條wait()語(yǔ)句時(shí),它會(huì)一直阻塞到接到通知(

3、notify()、被中斷或經(jīng)過(guò)了指定毫秒時(shí)間為止(若制定了超時(shí)值的話)線程阻塞與不同I/O的方式有多種。常見(jiàn)的一種方式是InputStream的read()方法,該方法一直阻塞到從流中讀取一個(gè)字節(jié)的數(shù)據(jù)為止,它可以無(wú)限阻塞,因此不能指定超時(shí)時(shí)間線程也可以阻塞等待獲取某個(gè)對(duì)象鎖的排他性訪問(wèn)權(quán)限(即等待獲得synchronized語(yǔ)句必須的鎖時(shí)阻塞)。2、線程的種類守護(hù)線程與線程阻塞的四種情況Java中有兩類線程:User Thread(用戶線程)、Daemon Thread(守護(hù)線程)用戶可以用Thread的setDaemon(true)方法設(shè)置當(dāng)前線程為守護(hù)線程。守護(hù)線程是否已經(jīng)完成了預(yù)期的服

4、務(wù)任務(wù)。一旦所有的用戶線程退出了,虛擬機(jī)也就退出運(yùn)行了。因此,不要在守護(hù)線程中執(zhí)行業(yè)務(wù)邏輯操作(比如對(duì)數(shù)據(jù)的讀寫等)。、setDaemon(true)必須在調(diào)用線程的start()方法之前設(shè)置,否則會(huì)跑出IllegalThreadStateException異常。在守護(hù)線程中產(chǎn)生的新線程也是守護(hù)線程。不要認(rèn)為所有的應(yīng)用都可以分配給守護(hù)線程來(lái)進(jìn)行服務(wù),比如讀寫操作或者計(jì)算邏輯。3、線程所操作的數(shù)據(jù)同步問(wèn)題:4、可重入內(nèi)置鎖每個(gè)Java對(duì)象都可以用做一個(gè)實(shí)現(xiàn)同步的鎖,這些鎖被稱為內(nèi)置鎖或監(jiān)視器鎖。線程在進(jìn)入同步代碼塊之前會(huì)自動(dòng)獲取鎖,并且在退出同步代碼塊時(shí)會(huì)自動(dòng)釋放鎖。獲得內(nèi)置鎖的唯一途徑就是進(jìn)入

5、由這個(gè)鎖保護(hù)的同步代碼塊或方法。某一個(gè)持有同步對(duì)象鎖的線程可以多次進(jìn)入這個(gè)同步代碼塊或方法。即同步對(duì)象鎖可以重入!同一個(gè)線程在調(diào)用本類中其他synchronized方法/塊或父類中的synchronized方法/塊時(shí),都不會(huì)阻礙該線程地執(zhí)行,因?yàn)榛コ怄i時(shí)可重入的。6、Java內(nèi)存模型在當(dāng)前的Java內(nèi)存模型下,線程可以把變量保存在本地內(nèi)存(比如機(jī)器的寄存器)中,而不是直接在主存中進(jìn)行讀寫。(本地內(nèi)存+共享主存)Volatile修飾的成員變量在每次被線程訪問(wèn)時(shí),都強(qiáng)迫從共享內(nèi)存中重讀該成員變量的值。而且,當(dāng)成員變量發(fā)生變化時(shí),強(qiáng)迫線程將變化值回寫到共享內(nèi)存。這樣在任何時(shí)刻,兩個(gè)不同的線程總是看到

6、某個(gè)成員變量的同一個(gè)值。而volatile關(guān)鍵字就是提示JVM:對(duì)于這個(gè)成員變量,不能保存它的私有拷貝,而應(yīng)直接與共享成員變量交互。volatile型變量的特殊規(guī)則:1、保證此變量對(duì)所有線程的可見(jiàn)性。需要注意,volatile變量的寫操作除了對(duì)它本身的讀操作可見(jiàn)外,volatile寫操作之前的所有共享變量均對(duì)volatile讀操作之后的操作可見(jiàn)2、禁止指令重排序優(yōu)化final域能確保初始化過(guò)程的安全性,從而可以不受限制地訪問(wèn)不可變對(duì)象,并在共享這些對(duì)象時(shí)無(wú)須同步因此在編碼時(shí),不需要將long和double變量專門聲明為volatile。主內(nèi)存與工作內(nèi)存Java內(nèi)存模型規(guī)定所有的變量都存儲(chǔ)在主內(nèi)

7、存中,而每條線程還有自己的工作內(nèi)存,線程的工作內(nèi)存中保存了該線程使用到的變量的主內(nèi)存副本拷貝,線程對(duì)變量的所有操作(讀取、賦值等)都必須在工作內(nèi)存中進(jìn)行,而不能直接讀寫主內(nèi)存中的變量。根據(jù)Java虛擬機(jī)規(guī)范的規(guī)定,volatile變量依然有共享內(nèi)存的拷貝,但是由于它特殊的操作順序性規(guī)定從工作內(nèi)存中讀寫數(shù)據(jù)前,必須先將主內(nèi)存中的數(shù)據(jù)同步到工作內(nèi)存中,所有看起來(lái)如同直接在主內(nèi)存中讀寫訪問(wèn)一般,因此這里的描述對(duì)于volatile也不例外不允許一個(gè)線程丟棄它的最近的assign操作,即變量在工作內(nèi)存中改變了之后必須把該變化同步回主內(nèi)存。如果對(duì)一個(gè)變量執(zhí)行l(wèi)ock操作,將會(huì)清空工作內(nèi)存中此變量的值,在執(zhí)

8、行引擎使用這個(gè)變量前,需要重新執(zhí)行l(wèi)oad或assign操作初始化變量的值。對(duì)一個(gè)變量執(zhí)行unlock操作之前,必須先把此變量同步回主內(nèi)存(7、輕量級(jí)同步volatile是一種稍弱的同步機(jī)制,在訪問(wèn)volatile變量時(shí)不會(huì)執(zhí)行加鎖操作,也就不會(huì)執(zhí)行線程阻塞,因此volatilei變量是一種比synchronized關(guān)鍵字更輕量級(jí)的同步機(jī)制。使用建議:在兩個(gè)或者更多的線程需要訪問(wèn)的成員變量上使用volatile。當(dāng)要訪問(wèn)的變量已在synchronized代碼塊中,或者為常量時(shí),沒(méi)必要使用volatile。由于使用volatile屏蔽掉了JVM中必要的代碼優(yōu)化,所以在效率上比較低,因此一定在必要

9、時(shí)才使用此關(guān)鍵字。假如有兩個(gè)線程分別讀寫volatile變量時(shí),線程A寫入了某volatile變量,線程B在讀取該volatile變量時(shí),便能看到線程A對(duì)該volatile變量的寫入操作,關(guān)鍵在這里,它不僅會(huì)看到對(duì)該volatile變量的寫入操作,A線程在寫volatile變量之前所有可見(jiàn)的共享變量,在B線程讀同一個(gè)volatile變量后,都將立即變得對(duì)B線程可見(jiàn)。happenbefore規(guī)則介紹其意思就是說(shuō),在發(fā)生操作B之前,操作A產(chǎn)生的影響都能被操作B觀察到,“影響”包括修改了內(nèi)存中共享變量的值、發(fā)送了消息、調(diào)用了方法等,它與時(shí)間上的先后發(fā)生基本沒(méi)有太大關(guān)系。線程啟動(dòng)規(guī)則:Thread對(duì)象

10、的start()方法happenbefore此線程的每一個(gè)動(dòng)作。8、同步鎖說(shuō)明當(dāng)線程擁有這個(gè)鎖標(biāo)記時(shí)才能訪問(wèn)這個(gè)資源,沒(méi)有鎖標(biāo)記便進(jìn)入鎖池。任何一個(gè)對(duì)象系統(tǒng)都會(huì)為其創(chuàng)建一個(gè)互斥鎖,這個(gè)鎖是為了分配給線程的,防止打斷原子操作。每個(gè)對(duì)象的鎖只能分配給一個(gè)線程,因此叫做互斥鎖。如果同一個(gè)方法內(nèi)同時(shí)有兩個(gè)或更多線程,則每個(gè)線程有自己的局部變量拷貝。類的每個(gè)實(shí)例都有自己的對(duì)象級(jí)別鎖訪問(wèn)同一個(gè)類的不同實(shí)例對(duì)象中的同步代碼塊,不存在阻塞等待獲取對(duì)象鎖的問(wèn)題,因?yàn)樗鼈儷@取的是各自實(shí)例的對(duì)象級(jí)別鎖,相互之間沒(méi)有影響。持有一個(gè)對(duì)象級(jí)別鎖不會(huì)阻止該線程被交換出來(lái),也不會(huì)阻塞其他線程訪問(wèn)同一示例對(duì)象中的非synchr

11、onized代碼。持有對(duì)象級(jí)別鎖的線程會(huì)讓其他線程阻塞在所有的synchronized代碼外。使用synchronized(obj)同步語(yǔ)句塊,可以獲取指定對(duì)象上的對(duì)象級(jí)別鎖。類級(jí)別鎖被特定類的所有示例共享,它用于控制對(duì)static成員變量以及static方法的并發(fā)訪問(wèn)。具體用法與對(duì)象級(jí)別鎖相似。10、多線程環(huán)境中安全使用集合API最初設(shè)計(jì)的Vector和Hashtable是多線程安全的。在Collections類 中有多個(gè)靜態(tài)方法,它們可以獲取通過(guò)同步方法封裝非同步集合而得到的集合:public static List synchronizedList(list l)List list =

12、Collection.synchronizedList(new ArrayList();注意,ArrayList實(shí)例馬上封裝起來(lái),不存在對(duì)未同步化ArrayList的直接引用(即直接封裝匿名實(shí)例)。這是一種最安全的途徑。如果另一個(gè)線程要直接引用ArrayList實(shí)例,它可以執(zhí)行非同步修改。從內(nèi)存可見(jiàn)性的角度看,寫入volatile變量相當(dāng)于退出同步代碼塊,而讀取volatile變量相當(dāng)于進(jìn)入同步代碼塊。、volatile變量是一種稍弱的同步機(jī)制在訪問(wèn)volatile變量時(shí)不會(huì)執(zhí)行加鎖操作,因此也就不會(huì)使執(zhí)行線程阻塞,因此volatile變量是一種比synchronized關(guān)鍵字更輕量級(jí)的同步機(jī)

13、制。原因是聲明為volatile的簡(jiǎn)單變量如果當(dāng)前值與該變量以前的值相關(guān),那么volatile關(guān)鍵字不起作用,也就是說(shuō)如下的表達(dá)式都不是原子操作:“count+”、“count = count+1”。當(dāng)且僅當(dāng)滿足以下所有條件時(shí),才應(yīng)該使用volatile變量:1、對(duì)變量的寫入操作不依賴變量的當(dāng)前值,或者你能確保只有單個(gè)線程更新變量的值。2、該變量沒(méi)有包含在具有其他變量的不變式中。三、死鎖問(wèn)題遵循以下原則有助于規(guī)避死鎖:1、只在必要的最短時(shí)間內(nèi)持有鎖,考慮使用同步語(yǔ)句塊代替整個(gè)同步方法;2、盡量編寫不在同一時(shí)刻需要持有多個(gè)鎖的代碼,如果不可避免,則確保線程持有第二個(gè)鎖的時(shí)間盡量短暫;3、創(chuàng)建和使

14、用一個(gè)大鎖來(lái)代替若干小鎖,并把這個(gè)鎖用于互斥,而不是用作單個(gè)對(duì)象的對(duì)象級(jí)別鎖;四、線程通信在調(diào)用wait()之前,線程必須要獲得該對(duì)象的對(duì)象級(jí)別鎖,即只能在同步方法或同步塊中調(diào)用wait()方法。進(jìn)入wait()方法后,當(dāng)前線程釋放鎖。notify() 該方法也要在同步方法或同步塊中調(diào)用,即在調(diào)用前,線程也必須要獲得該對(duì)象的對(duì)象級(jí)別鎖,的如果調(diào)用notify()時(shí)沒(méi)有持有適當(dāng)?shù)逆i,也會(huì)拋出IllegalMonitorStateException。notify后,當(dāng)前線程不會(huì)馬上釋放該對(duì)象鎖,wait所在的線程并不能馬上獲取該對(duì)象鎖,要等到程序退出synchronized代碼塊后,當(dāng)前線程才會(huì)釋

15、放鎖,wait所在的線程也才可以獲取該對(duì)象鎖),但不驚動(dòng)其他同樣在等待被該對(duì)象notify的線程們。當(dāng)?shù)谝粋€(gè)獲得了該對(duì)象鎖的wait線程運(yùn)行完畢以后,它會(huì)釋放掉該對(duì)象鎖,此時(shí)如果該對(duì)象沒(méi)有再次使用notify語(yǔ)句,則即便該對(duì)象已經(jīng)空閑,其他wait狀態(tài)等待的線程由于沒(méi)有得到該對(duì)象的通知,會(huì)繼續(xù)阻塞在wait狀態(tài),直到這個(gè)對(duì)象發(fā)出一個(gè)notify或notifyAll。這里需要注意:它們等待的是被notify或notifyAll,而不是鎖。這與下面的notifyAll()方法執(zhí)行后的情況不同。notifyAll使所有原來(lái)在該對(duì)象上wait的線程統(tǒng)統(tǒng)退出wait的狀態(tài)(即全部被喚醒,不再等待noti

16、fy或notifyAll,但由于此時(shí)還沒(méi)有獲取到該對(duì)象鎖,因此還不能繼續(xù)往下執(zhí)行),變成等待獲取該對(duì)象上的鎖,一旦該對(duì)象鎖被釋放(notifyAll線程退出調(diào)用了notifyAll的synchronized代碼塊的時(shí)候),他們就會(huì)去競(jìng)爭(zhēng)。如果其中一個(gè)線程獲得了該對(duì)象鎖,它就會(huì)繼續(xù)往下執(zhí)行,在它退出synchronized代碼塊,釋放鎖后,其他的已經(jīng)被喚醒的線程將會(huì)繼續(xù)競(jìng)爭(zhēng)獲取該鎖,一直進(jìn)行下去,直到所有被喚醒的線程都執(zhí)行完畢。如果線程調(diào)用了對(duì)象的wait()方法,那么線程便會(huì)處于該對(duì)象的等待池中,等待池中的線程不會(huì)去競(jìng)爭(zhēng)該對(duì)象的鎖。當(dāng)有線程調(diào)用了對(duì)象的notifyAll()方法(喚醒所有wai

17、t線程)或notify()方法(只隨機(jī)喚醒一個(gè)wait線程),被喚醒的的線程便會(huì)進(jìn)入該對(duì)象的鎖池中,鎖池中的線程會(huì)去競(jìng)爭(zhēng)該對(duì)象鎖。優(yōu)先級(jí)高的線程競(jìng)爭(zhēng)到對(duì)象鎖的概率大,假若某線程沒(méi)有競(jìng)爭(zhēng)到該對(duì)象鎖,它還會(huì)留在鎖池中,唯有線程再次調(diào)用wait()方法,它才會(huì)重新回到等待池中。而競(jìng)爭(zhēng)到對(duì)象鎖的線程則繼續(xù)往下執(zhí)行,直到執(zhí)行完了synchronized代碼塊,它會(huì)釋放掉該對(duì)象鎖,這時(shí)鎖池中的線程會(huì)繼續(xù)競(jìng)爭(zhēng)該對(duì)象鎖??偨Y(jié):在使用線程的等待/通知機(jī)制時(shí),一般都要配合一個(gè)boolean變量值(或者其他能夠判斷真假的條件),在notify之前改變?cè)揵oolean變量的值,讓wait返回后能夠退出while循環(huán)(

18、一般都要在wait方法外圍加一層while循環(huán),以防止早期通知),或在通知被遺漏后,不會(huì)被阻塞在wait方法處。這樣便保證了程序的正確性。五、并發(fā)新特性1、一般來(lái)說(shuō),CachedTheadPool在程序執(zhí)行過(guò)程中通常會(huì)創(chuàng)建與所需數(shù)量相同的線程,然后在它回收舊線程時(shí)停止創(chuàng)建新線程,因此它是合理的Executor的首選,只有當(dāng)這種方式會(huì)引發(fā)問(wèn)題時(shí)(比如需要大量長(zhǎng)時(shí)間面向連接的線程時(shí)),才需要考慮用FixedThreadPool。服務(wù)端面向連接:public static ExecutorService newFixedThreadPool(int nThreads)Executor執(zhí)行Runnable任務(wù)Executor執(zhí)行Callable任務(wù)在Java 5之后,任務(wù)分兩類:一類是實(shí)現(xiàn)了Runnable接

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(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)論