5:Java并發(fā)編程基礎(chǔ)

1:線程

(1)線程也叫輕量級進程。它擁有各自的計數(shù)器、堆棧和局部變量等屬性,并且能夠訪問共享的內(nèi)存變量。

(2)一個java程序的運行不僅僅是main()方法的運行,而是main線程和多個其他線程的同時運行。

(3)如果要設(shè)置線程的優(yōu)先級,那么需要注意:針對頻繁阻塞(休眠或者I/O操作)的線程需要設(shè)置較高的優(yōu)先級;而偏重計算(需要較多CPU時間或者偏運算)的線程則設(shè)置較低的優(yōu)先級,確保處理器不會被獨占。

(4)注意:線程優(yōu)先級不能作為程序正確性的依賴,因為操作系統(tǒng)可以完全不用理會java線程對于優(yōu)先級的設(shè)定。

博客:jstack工具使用?http://blog.csdn.net/fenglibing/article/details/6411999

(5)java線程的運行生命周期,在給定的某一個時刻,線程只能處于一個狀態(tài)。

下面是JAVA線程狀態(tài)變遷圖:


說明:

NEW狀態(tài)—一個被創(chuàng)建的線程,但是還沒有調(diào)用start方法。

BLOCKED狀態(tài)—一個線程因為等待臨界區(qū)的鎖被阻塞產(chǎn)生的狀態(tài)。(Lock或者synchronize關(guān)鍵字產(chǎn)生的狀態(tài)。)

WAITING狀態(tài)—一個線程進入了鎖,但是需要等待其他線程執(zhí)行某些操作,時間不確定。(當(dāng)wait,join,park方法調(diào)用時,進入waiting狀態(tài),前提是這個線程已經(jīng)擁有鎖啦。)

TIMED_WAITTING狀態(tài)—一個線程進入了鎖,但是需要等待其他線程執(zhí)行某些操作,時間確定。(通過sleep或者wait timeout方法進入的限期等待的狀態(tài)。)

TERMINATED狀態(tài)—退出

注意容易混淆的概念:阻塞在JUC包中LOCK接口的線程狀態(tài)卻是等待狀態(tài),因為JUC包中LOCK接口對于阻塞的實現(xiàn)均使用了LockSupport類中的相關(guān)方法。

(5)Daemon線程,當(dāng)java虛擬機中不存在非Daemon線程的時候,java虛擬機將會退出。

注意1:Daemon屬性需要在啟動線程之前設(shè)置,不能在啟動線程之后設(shè)置。

注意2:在構(gòu)建Daemon線程時,不能依靠finally塊中的內(nèi)容來確保執(zhí)行關(guān)閉或清理資源的邏輯。

2:啟動和終止線程

(1)線程的構(gòu)建記住一句話:一個新構(gòu)造的線程對象是由其parent線程來進行空間分配的,而child線程繼承了parent是否為Daemon、優(yōu)先級和加載資源的contextClassLoader以及可繼承的ThreadLocal,同時還會分配一個唯一的ID來標(biāo)識這個child線程。至此,一個能夠運行的線程對象就初始化好啦,在堆內(nèi)存中等待著運行。

(2)中斷?簡單的說:中斷好比其他線程對該線程打了招呼,其他線程通過調(diào)用該線程的interrupt()方法對其進行中斷操作。

(3)廢棄的API:suspend()暫停、resume()恢復(fù)、stop()停止,為啥廢棄呢?因為持有鎖,不釋放,可能導(dǎo)致死鎖。致命的的是也不支持中斷。

(4)如何安全的終止線程呢?一種方法:使用中斷來取消或停止任務(wù)。另一種方法:利用一個boolean變量來控制是否需要停止任務(wù)并終止該線程。

3:線程間通信

(1)一個線程一旦開始運行,就擁有自己的棧空間。

(2)volatile可以用來修飾字段(成員變量),就是告知程序任何對該變量的訪問均需要從共享內(nèi)存中獲取,而對它的改變必須同步刷新回共享內(nèi)存,它能保證所有線程對變量訪問的可見性。

(3)sychronized實現(xiàn)原理:對一個對象的監(jiān)視器(monitor)進行獲取,而這個獲取過程是排他的。也就是同一時刻只能有一個線程獲取到由synchronized所保護對象的監(jiān)視器。

對象、對象監(jiān)視器、同步隊列和執(zhí)行線程之間的關(guān)系


任意線程對Object(Object由synchronized保護)的訪問,首先要獲得Object的監(jiān)視器。如果獲取失敗,線程進入同步隊列,線程狀態(tài)變?yōu)锽LOCKED。當(dāng)訪問Object的前驅(qū)(獲得了鎖的線程)釋放了鎖,則該釋放操作喚醒阻塞在同步隊列中的線程,使其嘗試對監(jiān)視器的獲取。

(3)等待/通知機制是任意java對象都具備的,因為定義在Object里面。下面是等待/通知相關(guān)方法:


使用wait()、notify()、notifyAll()時需要注意的細(xì)節(jié):

1)使用wait()、notify()、notifyAll()時需要先調(diào)用對象加鎖。

2)調(diào)用wait()方法后,線程狀態(tài)由RUNNING變?yōu)閃AITING,并將當(dāng)前線程放置到等待隊列中。

3)notify()或notifyAll()方法調(diào)用后,等待線程依舊不會從wait()返回,需要調(diào)用notify()或notifyAll()的線程釋放鎖之后,等待線程才有機會從wait()返回。

4)notify()方法將等待隊列中的一個等待線程從等待隊列中移到同步隊列中,而notifyAll()方法則是將等待隊列中所有的線程全部移到同步隊列,被移動的線程狀態(tài)由WAITING變?yōu)锽LOCKED。

5)從wait()方法返回的前期是或得了調(diào)用對象的鎖。

(4)等待/通知的經(jīng)典范式,分別針對等待方(消費者)和通知方(生產(chǎn)者)

等待方遵循如下原則:

a:獲取對象的鎖

b:如果條件不滿足,那么調(diào)用對象的wait()方法,被通知后仍要檢查條件。

c:條件滿足則執(zhí)行對應(yīng)邏輯。

通知方遵循如下原則:

a:獲得對象的鎖。

b:改變條件

c:通知所有等待在對象上的線程。

(5)管道輸入/輸出流和普通文件的輸入/輸出流或者網(wǎng)絡(luò)輸入/輸出流不同處:它主要用于線程之間的數(shù)據(jù)傳輸,而傳輸?shù)拿浇闉閮?nèi)存。

PipedOutputStream、PipedInputStream面向字節(jié)

PipedWriter、PipedReader面向字符

(6)Thread.join():如果一個線程A執(zhí)行了thread.join()語句,表示:當(dāng)前線程A等待thread線程終止后才從thread.join()返回。這里涉及了等待/通知機制(等待前驅(qū)線程結(jié)束,接收前驅(qū)線程結(jié)束通知)

(7)ThreadLocal(線程變量)的使用。它是一個以ThreadLocal對象為鍵、任意對象為值的存儲結(jié)構(gòu)。這個結(jié)構(gòu)會被附帶在線程上,也就是說一個線程可以根據(jù)一個ThreadLocal對象查詢到綁定在這個線程上的一個值。

4:線程應(yīng)用實例

(1)等待超時模式?(使用等待超時模式來構(gòu)造一個簡單的數(shù)據(jù)庫連接池。)

(2)線程池技術(shù)?(使用線程池技術(shù)構(gòu)建一個簡單的web服務(wù)器。)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容