黑馬程序員——多線程

------- <a href="http://www.itheima.com" target="blank">android培訓</a>、<a href="http://www.itheima.com" target="blank">java培訓</a>、期待與您交流! ----------

線程,指的是在程序執行過程中沿一條線索逐條語句按順序執行的流程。main函數就是一個線程,叫做主線程。在多線程開發過程中,隨着主函數的進行,可以隨時開啓一個獨立執行的線程。多線程可同時執行,同時執行的本質可以是CPU多核同時執行多個任務,也可以是CPU內核在多任務間的飛速切換。在Java中,線程被預定義包裝成了java類庫中的類,該類是java.lang.Thread,Thread實現Runnable接口(run()方法),當線程啓動時,執行的就是run()方法。

線程類必須是Thread類或其子類。run()方法中的內容,是自定義線程類最核心的內容,可以在繼承自Thread的類中重寫run()方法,也可以通過定製一個實現了Runnable接口的類(實現其run()方法),再通過在Thread構造方法中傳入一個該類對象的方式建立自定義線程。

線程的狀態:

在Java當中,線程通常都有五種狀態,創建、就緒、運行、阻塞和死亡。 
  第一是創建狀態。在生成線程對象,並沒有調用該對象的start方法,這是線程處於創建狀態。 
  第二是就緒狀態。當調用了線程對象的start方法之後,該線程就進入了就緒狀態,但是此時線程調度程序還沒有把該線程設置爲當前線程,此時處於就緒狀態。在線程運行之後,從等待或者睡眠中回來之後,也會處於就緒狀態。 
  第三是運行狀態。線程調度程序將處於就緒狀態的線程設置爲當前線程,此時線程就進入了運行狀態,開始運行run函數當中的代碼。 
  第四是阻塞狀態。線程正在運行的時候,被暫停,通常是爲了等待某個時間的發生(比如說某項資源就緒)之後再繼續運行。sleep,suspend,wait等方法都可以導致線程阻塞。 
  第五是死亡狀態。如果一個線程的run方法執行結束或者調用stop方法後,該線程就會死亡。對於已經死亡的線程,無法再使用start方法令其進入就緒。 

併發編程引發的問題是不確定的,有可能在程序檢測時並未發生,在客戶使用的過程中卻出現。Java使用併發系統會共享諸如內存和I/O這樣的資源,因此編寫多線程程序最基本的困難在於在協調不同線程驅動的任務之間對這些資源的使用,以使得這些資源不會同時被多個任務訪問。
併發需要付出代價,包含複雜性代價,但是這些代價與程序設計、資源負載均衡以及用戶使用方便方面的改進相比,就顯得微不足道了。

Executor:
Java SE5對java.util.concurren包中的執行器(Executor)能管理Thread對象,簡化編程。
將Runnable類對象作爲參數傳入Executor對象的execute(Runnable r)方法可以啓動新的線程執行此Runnable中的run()方法。

ExectorService  exec=Executors.newCachedThreadPool();
ExectorService  exec=Executors.newFixedThreadPool();
ExectorService  exec=Executors.newSingleThreadExecutor();
exec.execute(r);

將Callable類(具有返回值的泛型類,其call()方法相當於Runnable類的run()方法,能產生線程;Callable<T>的返回值是T類對象。)對象作爲參數傳入ExecutorService(Executor子類)對象的submit(Callable<T>  c)方法,submit()方法可以在該Callable<T>的call()方法執行完畢時返回一個Future<T>類型對象。Future<T>對象的get()方法能獲得T值,但該get()方法是一個阻塞式方法,只有在call()方法執行完畢時get()才返回值,Future<T>的isDone()方法可以用來判斷Callable<T>的call()方法是否已經執行完畢並返回值。

Callable<T>  c=new Callable<T>(){
public T call(){
.....
return (T)t;
}
};
Future<T> fu=exec.submit(c);
if(fu.isDone)
T t=fu.get();
優先級:
優先級的高低決定了各線程執行頻率的高低,而不是決定各線程的執行順序。Thread的getPriority()和setPriority()方法可以用來獲取和設置線程的優先級,但在大多數時間裏,

所有線程都應該以默認的優先級運行,試圖操縱線程優先級通過是種錯誤。JDK有10個優先級。

讓步:
Thread的yield()方法會給線程調度器一個暗示:本線程的工作可以暫停一下了,讓別的線程繼續執行。但這只是一種暗示,沒有任何機制保證它一定被線程調度器採納。

後臺線程:
當所有非後臺線程執行結束後,程序會自動終止所有未執行完畢的後臺程序。Thread的setDaemon(boolean b)和isDaemon()可以用來設置和判斷線程的後臺性。
由後臺線程創建的線程自動被設置成後臺線程。
後臺線程在被迫終止時,其中的finally子句不會得到執行。


線程中斷:A、B爲線程,在A中調用B.join();將使A線程中斷,直到B線程執行完畢。在線程內部調用Thread.sleep(int n)將使該線程睡眠中斷n毫秒,在線程內部調用Thread.wait(),將使該線程進程等待狀態,直到被喚醒(notify()方法),當A線程處於中斷狀態的任意一種狀態時,B線程調用了A.interrupt()方法,A的中斷狀態將被消除,同時A中拋出InterruptedException。線程同步:爲解決多線程間共享資源的問題,可以使用synchronized方法和代碼塊。返回值前標註synchronized的方法是同步的,其鎖是該方法的對象(this),同一個對象的所有同步方法用的都是該對象本身,這些方法是同步的;同步代碼塊需指出作爲鎖的對象:
synchronized(obj)//obj是鎖
{
    .....
    代碼塊
    .....
}
使用同一個對象作爲鎖的同步代碼塊之間也是同步的。
Lock類:
Java SE5 java.util.concurrent類中的locks包中有Lock接口。該類具有實現類ReentrantLock,Lock類對象調用lock()和unlock()方法標記同步代碼塊的開始和結束,即鎖定和解鎖。通常將解鎖放在try—finally的finally子句中。
Condition類:
可以通過在Condition上調用await()掛起一個任務,當外部條件變化後,可以通過調用signal()方法重新喚醒這個任務。Condition對象通過ReentrantLock的newCondition()方法獲得,並且await()和signal()方法要位於該Lock對象的鎖定範圍內。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章