標籤:alt 建立 sync 計算 最簡 操作 需要 裝置 bool
一、說明
周末抽空重新學習了下多線程,為了方便以後查閱,寫下學習筆記。
有效利用多線程的關鍵是理解程式是並發執行而不是串列執行的。例如:程式中有兩個子系統需要並發執行,這時候需要利用多線程編程。
通過多線程的使用,可以編寫出非常高效的程式。但如果建立了太多的線程,程式執行的效率反而會降低。
同時內容相關的切換開銷也很重要,如果建立太多的線程,CPU花費在內容相關的切換時間將對於執行程式的時間。
二、Java多線程編程
在學習多線程時,我們應該首先明白另外一個概念。
進程:是電腦中的程式關於某資料集合上的一次運行活動,是系統進行資源分派和調度的基本單位,是作業系統結構的基礎。在當代面向線程設計的電腦結構中,進程是線程的容器。程式是指令、資料及其組織形式的描述,進程是程式的實體。一個進程包括由作業系統分配的記憶體空間,包含一個或多個線程。一個線程不能獨立的存在,它必須是進程的一部分。一個進程一直運行,直到所有的非守候線程都結束運行後才能結束。
線程是一個動態執行的過程,它也有一個從產生到死亡的過程。顯示的是線程的生命週期:
說明:
建立狀態:
使用 new 關鍵字和 Thread 類或其子類建立一個線程對象後,該線程對象就處於建立狀態。它保持這個狀態直到程式 start() 這個線程。
就緒狀態:
當線程對象調用了start()方法之後,該線程就進入就緒狀態。就緒狀態的線程處於就緒隊列中,要等待JVM裡線程調度器的調度。
運行狀態:
如果就緒狀態的線程擷取 CPU 資源,就可以執行 run(),此時線程便處於運行狀態。處於運行狀態的線程最為複雜,它可以變為阻塞狀態、就緒狀態和死亡狀態。
阻塞狀態:
如果一個線程執行了sleep(睡眠)、suspend(掛起)等方法,失去所佔用資源之後,該線程就從運行狀態進入阻塞狀態。在睡眠時間已到或獲得裝置資源後可以重新進入就緒狀態。可以分為三種:
等待阻塞:運行狀態中的線程執行 wait() 方法,使線程進入到等待阻塞狀態。
同步阻塞:線程在擷取 synchronized 同步鎖失敗(因為同步鎖被其他線程佔用)。
其他阻塞:通過調用線程的 sleep() 或 join() 發出了 I/O 請求時,線程就會進入到阻塞狀態。當sleep() 狀態逾時,join() 等待線程終止或逾時,或者 I/O 處理完畢,線程重新轉入就緒狀態。
死亡狀態:
一個運行狀態的線程完成任務或者其他終止條件發生時,該線程就切換到終止狀態。
每一個 Java 線程都有一個優先順序,這樣有助於作業系統確定線程的調度序。
Java 線程的優先順序是一個整數,其取值範圍是 1 (Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY )。預設情況下,每一個線程都會分配一個優先順序 NORM_PRIORITY(5)。
具有較高優先順序的線程對程式更重要,並且應該在低優先順序的線程之前分配處理器資源。但是,線程優先順序不能保證線程執行的順序,而且非常依賴於平台。
Java提供了三種建立線程的方法:
通過實現Runnable介面;
通過繼承Thread類本身;
通過Callable和Future建立線程;
1、通過實現Runnable介面來建立線程
建立一個線程,最簡單的方法是建立一個實現Runnable介面的類。
為了實現Runnable,一個類只需要執行一個方法調用run(),聲明如下:
Public void run();
在建立一個實現Runnable介面的類之後,你可以在類中執行個體化一個線程對象。
Thread(Runnable threadOb,String threadName);
threadOb 是一個實現Runnable介面的類的執行個體,並且threadName指定新線程的名字。
新線程建立之後,調用start()方法才會運行。
Void start();
舉例如下:
2、通過繼承Thread來建立線程
建立一個線程的第二種方法是建立一個新的類,該類繼承 Thread 類,然後建立一個該類的執行個體。
繼承類必須重寫 run() 方法,該方法是新線程的進入點。它也必須調用 start() 方法才能執行。
該方法儘管被列為一種多線程實現方式,但是本質上也是實現了 Runnable 介面的一個執行個體。
舉例如下:
3、通過Callable和Future建立線程
步驟如下:
建立Callable介面的實作類別,並實現call()方法,該call()方法將作為線程執行體,並有傳回值。
建立Callable實作類別的執行個體,使用FutureTask類來封裝Callable對象,該FutureTask對象封裝了該Callable對象的call()方法的傳回值。
使用FutureTask對象作為Thread對象的target建立並啟動新線程。
調用FutureTask對象的get()方法來獲得子線程執行結束後的傳回值。
說明:建立線程的三種方式的對比
採用實現Runnable、Callable介面的方式建立多線程時,線程類只是實現了Runnable介面或Callable介面,還可以繼承其他類。
使用繼承Thread類的方式建立多線城時,編寫簡單,如果需要訪問當前線程時,則無需使用Thread.currentThread()方法,直接使用this即可獲得當前線程。
備忘:常用的Thread()方法
Public void start() : 使該線程開始執行,Java虛擬機器調用該線程的run方法。
Public void run():如果該線程是使用獨立的Runnable運行物件建構的,則調用該Runnable對象的run方法;否則該方法不執行任何操作就返回。
Public final void setName(String name):改變線程名稱為name。
Public final void setPriority(int priority) :改變線程的優先順序
Public final void setDaemon(Boolean on):將該線程標記為守護線程或使用者線程。
Public final void join(long millisec):等待該線程終止的時間最長為毫秒。
Public void interruput() : 中斷線程。
Public final Boolean isAlive():測試線程是否處於活動狀態。
Public static void yield():暫停當前正在執行的線程對象,並執行其他線程。
Public static void sleep(long millisec): 在指定的毫秒數內讓正在執行的線程休眠。
Public static Boolean holdsLock(Object x):若且唯若當前線程在指定的對象上保持監視器鎖時,才返回true。
Public static Thread currentThread():返回對當前正在執行的線程對象的引用。
Public static void dumpStack():將當前線程的堆疊追蹤列印至標準錯誤流。
參考資料:
http://www.runoob.com/java/java-multithreading.html
Java多線程編程(學習筆記)