JAVA多線程

線程的4個狀態:

創建(new),就緒(runnable),阻塞(blocked),終止(dead)

Runnable接口:

定義了一個描述任務的方式,他具有任何內在的線程能力,使用它必須將它顯示的依附在線程上。

傳統的方法是將其傳遞給一個Thread的構造方法。

Thread對象:

當主線程創建Thread對象后,并沒有創建其對象的引用,在start()之后每個Thread都會注冊自己,并創建自己一個單獨的執行線程,在其執行完run()方法并死亡前是無法回收該對象的。

Exector:

線程池可以為我們管理Thread對象,相當于在客戶端與執行任務之間的一個間接層。

ExcetorService由Excetor的靜態方法創建。

newCachedThreadpool()會在程序中創建與任務數相同的線程, 然后在回收舊線程時才會停止創建新線程。當所需要的線程的數量過多影響到性能時應選用newFixedThreadpool();

newFixedThreadpool()可以指定線程數量的上限。

newSingleThreadExector()數量為1的FixedThreadpool,所有任務以隊列的形式一個個順序運行。

shutdown()方法防止其他任務提交給該Excetor.


Callable接口與Future:

是帶有返回值的Runnable接口,內部聲明的方法是call().一般情況下配合ExctoeService使用。Future就是對于具體的Runnable或者Callable任務的執行結果進行取消、查詢是否完成、獲取結果。必要時可以通過get方法獲取執行結果,該方法會阻塞直到任務返回結果。Future由ExecutorService.sumbit返回。

Future提供了三種功能:

1)判斷任務是否完成;

2)能夠中斷任務;

3)能夠獲取任務執行結果。

因為Future只是一個接口,所以是無法直接用來創建對象使用的,因此有FutureTask。

FutureTask:

publicclassFutureTaskimplementsRunnableFuture

FutureTask類實現了RunnableFuture接口,我們看一下RunnableFuture接口的實現:

publicinterfaceRunnableFutureextendsRunnable, Future {

voidrun();

}

可以看出RunnableFuture繼承了Runnable接口和Future接口,而FutureTask實現了RunnableFuture接口。所以它既可以作為Runnable被線程執行,又可以作為Future得到Callable的返回值。

FutureTask提供了2個構造器:

publicFutureTask(Callable callable) {

}

publicFutureTask(Runnable runnable, V result) {

}

事實上,FutureTask是Future接口的一個唯一實現類。


后臺線程:

調用setDaemon方法可以將線程設置成后臺線程,但是必須在線程start后才能起作用。當程序終止時就會殺死全部后臺線程。后臺線程派生出的子線程全部默認為后臺線程。


線程中捕獲異常:

線程中產生的異常不能夠在主線程捕獲。如果需要在主線程捕獲子線程產生的異常需要用到uncanughtException.

uncanughtException是一個接口。實現該接口,并調用Thread.setUncanughtExceptionHandle(..),就可以在指定的線程中捕獲其他線程產生的異常。


synchronized與Lock的區別:

ReentrantLock是Lock的一個實現,他允許嘗試獲得鎖但最終未獲得鎖,因為可以決定離開去做別事情。而synchronized則會等待鎖。因此ReentrantLock賦予了更細粒度的控制力。


原子性:

一個操作是原子性去取決于其底層的實現,因此是與操作系統有關,應避免使用原子性來替代線程同步。


線程的終止:

當線程被阻塞時(如調用了wait/sleep等方法時),可以使用 Thread.interrupt()方法打斷阻塞的狀態,當調用此方法后 Thread的 interrupted 標記被設置為 true. 此時如果你調用 interrupted()方法來測試中斷狀態(此方法會清空中斷狀態,也可以使用isInterrupted()來測試中斷狀態,這時中斷狀態不會被清空).

當調用 interrupte()方法時會拋出 InterruptedException,這時中斷狀態被清空.

線程被 sleep/wait 阻塞時可以被 interrupt,但如果線程被 IO或synchronized 阻塞則不可以被 interrupt,

線程間的協作:

我們上面講的主要是如何讓線程互斥的訪問一個共享的資源,現在要研究如何讓線程間進行協作,也就說二個線程有個先后,必須第一個線程完成后,第二個線程才能開始執行(像生產者與消費者)。

要完成上面所說的就要用到 Object.wait()/notify()/notifyAll()了.

wait/notify/notifyAll 的調用都必須在獲得這個對象的 monitor 時.

當wait 被調用時,當前線程被加入 wait set,這時這個線程不再被系統調度,直到有其它線程調用特定對象的notify或notifyAll方法時,此線程從wait set 中移除,開始被系統調度,但它必須再次獲得特定對象的monitor才能繼續。當獲得對象的monitor后,wait方法會返回,這時此線程會恢復到調用wait方法前的狀態.

注意: 當調用 wait()時會釋放對象鎖,而 sleep/yield 等方法不會釋放鎖.

wait/notify/notifyAll 及 synchronized 都是相對于一個對象來說的,都需要這個對象的鎖.

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容