多執行緒程式設計,處理多執行緒的併發問題(執行緒池)
執行緒物件是可以產生執行緒的物件。比如在
Java
平臺中Thread物件,Runnable物件。執行緒,是指正在執行的一個指點令序列。在java平臺上是指從一個執行緒物件的start()開始,執行run方法體中的那一段相對獨立的過程。相比於多程式,多執行緒的優勢有:
(1)程式之間不能共享資料,執行緒可以;
(2)系統建立程式需要為該程式重新分配系統資源,故建立執行緒代價比較小;
(3)Java語言內建了多執行緒功能支援,簡化了java多執行緒程式設計。
1、執行緒實現方式:
* 第一種方式:
* 1.自定義類,繼承Thread;
* 2.重寫run( )方法;
* 3.啟動執行緒:
* 1).例項化自定義執行緒物件;
* 2).呼叫自定義執行緒物件的start()方法啟動執行緒;
*
* 第二種方式:
* 1.自定義類,實現Runnable介面;
* 2.重寫run( )方法:
* 3.啟動執行緒:
* 1).例項化自定義的Runnable子類物件;
* 2).例項化一個Thread物件,將自定義物件作為引數傳給Thread的構造方法;
* 3).呼叫Thread物件的start()啟動執行緒;
區別:
一種是擴充套件java.lang.Thread類
另一種是實現java.lang.Runnable介面
好處:
在實際開發中通常以實現Runnable介面為主,因為實現Runnable介面相比繼承Thread類可以避免繼承的侷限,一個類可以繼承多個介面,適合於資源的共享。
執行緒和程式的區別:
程式:
每個程式都有獨立的程式碼和資料空間(程式上下文),程式間的切換會有較大的開銷,
一個程式包含1--n個執行緒。
(程式是資源分配的最小單位)。
執行緒:
同一類執行緒共享程式碼和資料空間,每個執行緒有獨立的執行棧和程式計數器(PC),執行緒切換開銷小。
(執行緒是cpu排程的最小單位)。
2、多執行緒
好處:
1.可以充分利用CPU資源;
2.對於執行緒中程式碼,可以獨立於"主執行緒"單獨執行,它不用等待前面的程式碼執行完畢;
也就意味著,我們的程式可以同時做多件事情;
問題:
1.多執行緒有幾種實現方案,分別是哪幾種?
* 三種:
* 1.繼承Thread,重寫run()方法;
* 2.實現Runnable介面,重寫run()方法;
* 3.(JDK5)實現Callable介面,重寫call()方法;
*
3.啟動一個執行緒是run()還是start()?它們的區別?
1).start()啟動執行緒;
2).run是普通方法,我們把執行緒中需要做的事情寫在這裡;
start方法用於啟動執行緒,它會呼叫run()方法;
4.sleep( )和wait( )方法的區別:
1).sleep:
a.屬於Thread類;
b.讓當前執行緒休眠指定的時間,當時間到,會自動醒來;
c.在同步方法中,不會釋放鎖;
2).wait:
a.屬於Object類;
b.可以指定時間,也可以不指定;當時間到時,或者使用notify()或notifyAll()方法後,會醒來;
c.在同步方法中,會釋放鎖;
5.為什麼wait( ),notify( ),notifyAll( )等方法都定義在Object類中:
1).因為任何物件都有可能被多執行緒併發訪問,所以,任何物件都有讓當前訪問的執行緒"等待"的權利,也有需要"喚醒"的義務;
6.執行緒的生命週期
新建:
用new關鍵字和Thread類或其子類建立一個執行緒物件後,該執行緒物件就處於新生狀態。
處於新生狀態的執行緒有自己的記憶體空間,通過呼叫start方法進入就緒狀態(runnable)。
就緒:
處於就緒狀態的執行緒已經具備了執行條件,但還沒有分配到CPU,處於執行緒就緒佇列,
等待系統為其分配CPU。
一旦獲得CPU,執行緒就進入執行狀態並自動呼叫自己的run方法。
執行:
處於執行狀態的執行緒最為複雜,它可以變為阻塞狀態、就緒狀態和死亡狀態。
阻塞:
處於執行狀態的執行緒在某些情況下,如執行了sleep(睡眠)方法,或等待IO裝置等資源,
將讓出CPU並暫時停止自己的執行,進入阻塞狀態。在阻塞狀態的執行緒不能進入就緒佇列。
死亡:
當執行緒的run()方法執行完,或者被強制性地終止,就認為它死去。
7."並行"與"併發":
1)."並行":是指多個執行緒在"某個時間段內",在同時執行;
2)."併發":是指多個執行緒在"某個時間點上",同時訪問一個共享資源;
3、併發
定義:
是指多個執行緒在"某個時間點上",同時訪問一個共享資源;
同步的方式:
1.synchronized:
1).同步程式碼塊;
即有synchronized關鍵字修飾的語句塊。
被該關鍵字修飾的語句塊會自動被加上內建鎖,從而實現同步
注:
同步是一種高開銷的操作,因此應該儘量減少同步的內容。
通常沒有必要同步整個方法,使用synchronized程式碼塊同步關鍵程式碼即可。
2).同步方法;
即有synchronized關鍵字修飾的方法。
由於java的每個物件都有一個內建鎖,當用此關鍵字修飾方法時,
內建鎖會保護整個方法。在呼叫該方法前,需要獲得內建鎖,否則就處於阻塞狀態。
2.(JDK5) ReentrantLock鎖:
在JavaSE5.0中新增了一個java.util.concurrent包來支援同步。
ReentrantLock類是可重入、互斥、實現了Lock介面的鎖,
它與使用synchronized方法和快具有相同的基本行為和語義,並且擴充套件了其能力。
常用方法有:
ReentrantLock() : 建立一個ReentrantLock例項
lock() : 獲得鎖
unlock() : 釋放鎖
注意:
ReentrantLock()還有一個可以建立公平鎖的構造方法,但由於能大幅度降低程式執行效率,不推薦使用
例子:
// 存錢
public void addMoney(int money) {
lock.lock();//上鎖
try{
count += money;
System.out.println(System.currentTimeMillis() + "存進:" + money);
}finally{
lock.unlock();//解鎖 }
}
3.使用特殊域變數(volatile)實現執行緒同步
a.volatile關鍵字為域變數的訪問提供了一種免鎖機制,
b.使用volatile修飾域相當於告訴虛擬機器該域可能會被其他執行緒更新,
c.因此每次使用該域就要重新計算,而不是使用暫存器中的值
d.volatile不會提供任何原子操作,它也不能用來修飾final型別的變數
好處:解決了併發性訪問的問題;
弊端:由於要處理執行緒的等待、阻塞等問題,所以效率會降低;
4、執行緒池
1).獲取執行緒池物件:JDK5新增了一個Executors工廠類來產生執行緒池,有如下幾個方法:
public static ExecutorService newCachedThreadPool():建立一個可根據需要建立新執行緒的執行緒池
public static ExecutorService newFixedThreadPool(int nThreads):建立一個可重用固定執行緒數的執行緒池
public static ExecutorService newSingleThreadExecutor():建立一個使用單個 worker 執行緒的 Executor
2).操作線城池:
這些方法的返回值是ExecutorService物件,該物件表示一個執行緒池,可以執行Runnable物件或者Callable物件代表的執行緒。
它提供瞭如下方法
Future<?> submit(Runnable task)
<T> Future<T> submit(Callable<T> task)
3).使用執行緒池的好處
第一:降低資源消耗。通過重複利用已建立的執行緒降低執行緒建立和銷燬造成的消耗。
第二:提高響應速度。當任務到達時,任務可以不需要的等到執行緒建立就能立即執行。
第三:提高執行緒的可管理性。執行緒是稀缺資源,如果無限制的建立,不僅會消耗系統資源,
還會降低系統的穩定性,使用執行緒池可以進行統一的分配,調優和監控。
但是要做到合理的利用執行緒池,必須對其原理了如指掌。
4).執行緒池的處理流程如下
- 首先執行緒池判斷基本執行緒池是否已滿?沒滿,建立一個工作執行緒來執行任務。滿了,則進入下個流程。
- 其次執行緒池判斷工作佇列是否已滿?沒滿,則將新提交的任務儲存在工作佇列裡。滿了,則進入下個流程。
- 最後執行緒池判斷整個執行緒池是否已滿?沒滿,則建立一個新的工作執行緒來執行任務,滿了,則交給飽和策略來處理這個任務。
5) .執行緒池的組成部分
一個比較簡單的執行緒池至少應包含執行緒池管理器、工作執行緒、任務列隊、任務介面等部分。
其中執行緒池管理器的作用是建立、銷燬並管理執行緒池,將工作執行緒放入執行緒池中。工作執行緒是一個可以迴圈執行任務的執行緒,在沒有任務是進行等待;任務列隊的作用是提供一種緩衝機制,將沒有處理的任務放在任務列隊中;任務介面是每個任務必須實現的介面,主要用來規定任務的入口、任務執行完後的收尾工作、任務的執行狀態等,工作執行緒通過該介面排程任務的執行。
執行緒池管理器至少有下列功能:建立執行緒池,銷燬執行緒池,新增新任務。
工作執行緒是一個可以迴圈執行任務的執行緒,在沒有任務時將等待。
任務介面是為所有任務提供統一的介面,以便工作執行緒處理。任務介面主要規定了任務的入口,任務執行完後的收尾工作,任務的執行狀態等。
6). 執行緒的終止(shutdown、shutdownnow)
ExecutorService執行緒池就提供了shutdown和shutdownNow這樣的生命週期方法來關閉執行緒池自身以及它擁有的所有執行緒。
shutdown:
(1)執行緒池的狀態變成SHUTDOWN狀態,此時不能再往執行緒池中新增新的任務,否則會丟擲RejectedExecutionException異常。
(2)執行緒池不會立刻退出,直到新增到執行緒池中的任務都已經處理完成,才會退出。
shutdown做了幾件事:
1. 檢查是否能操作目標執行緒
2. 將執行緒池狀態轉為SHUTDOWN
3. 中斷所有空閒執行緒
shutdownNow:
(1)執行緒池的狀態立刻變成STOP狀態,此時不能再往執行緒池中新增新的任務。
(2)終止等待執行的執行緒,並返回它們的列表;
(3)試圖停止所有正在執行的執行緒,試圖終止的方法是呼叫Thread.interrupt(),但是大家知道,
如果執行緒中沒有sleep 、wait、Condition、定時鎖等應用, interrupt()方法是無法中斷當前的執行緒的。
所以,ShutdownNow()並不代表執行緒池就一定立即就能退出,
它可能必須要等待所有正在執行的任務都執行完成了才能退出。
相關文章
- 多執行緒【執行緒池】執行緒
- 使用執行緒池優化多執行緒程式設計執行緒優化程式設計
- Java多執行緒——執行緒池Java執行緒
- java多執行緒與併發 - 執行緒池詳解Java執行緒
- Java併發 之 執行緒池系列 (1) 讓多執行緒不再坑爹的執行緒池Java執行緒
- java多執行緒9:執行緒池Java執行緒
- kuangshenshuo-多執行緒-執行緒池執行緒
- JavaThread多執行緒執行緒池Javathread執行緒
- Java多執行緒18:執行緒池Java執行緒
- 多執行緒之手撕執行緒池執行緒
- 多執行緒程式設計基礎(二)-- 執行緒池的使用執行緒程式設計
- Java多執行緒-執行緒池的使用Java執行緒
- 【java 多執行緒】多執行緒併發同步問題及解決方法Java執行緒
- 多執行緒併發篇——如何停止執行緒執行緒
- Android多執行緒之執行緒池Android執行緒
- 【Java】【多執行緒】執行緒池簡述Java執行緒
- java多執行緒系列之執行緒池Java執行緒
- 多執行緒------執行緒與程式/執行緒排程/建立執行緒執行緒
- C#多執行緒開發-執行緒池03C#執行緒
- 多執行緒-執行緒池的概述和使用執行緒
- Java多執行緒/併發12、多執行緒訪問static變數Java執行緒變數
- 【多執行緒高併發程式設計】二 實現多執行緒的幾種方式執行緒程式設計
- 併發程式設計之多執行緒執行緒安全程式設計執行緒
- 多執行緒與高併發(一)多執行緒入門執行緒
- 多執行緒與高併發(二)執行緒安全執行緒
- 併發與多執行緒之執行緒安全篇執行緒
- java多執行緒執行問題Java執行緒
- [短文速讀 -5] 多執行緒程式設計引子:程式、執行緒、執行緒安全執行緒程式設計
- C#多執行緒學習(四) 多執行緒的自動管理(執行緒池)C#執行緒
- C# 多執行緒學習(4) :多執行緒的自動管理(執行緒池)C#執行緒
- .NET多執行緒程式設計(1):多工和多執行緒 (轉)執行緒程式設計
- 多執行緒系列(三):執行緒池基礎執行緒
- C#多執行緒之旅(3):執行緒池C#執行緒
- 多執行緒-多執行緒常見的面試題執行緒面試題
- 多執行緒--執行緒管理執行緒
- Java多執行緒——執行緒Java執行緒
- 執行緒與多執行緒執行緒
- 多執行緒問題執行緒