進程和線程:
進程:是指一個內存中運行的應用程序,每個進程都有自己獨立的一塊內存空間,一個進程中可以有多個線程。比如在Windows系統中,一個運行的xx.exe就是一個進程。
Java程序的進程中有幾個線程:主線程、垃圾回收線程
線程:是指進程中的一個執行任務,一個進程中可以運行多個線程,多個線程可共享數據
進程與線程的區別:
1)進程有獨立的進程空間,進程中的數據存放空間(堆空間和棧空間)是獨立的。
2)線程的堆空間是共享的,棧空間是獨立的,線程消耗的資源也比進程小,相互之間可以影響的。
線程的生命週期:
1)新建(New):當程序創建了一個線程後,該線程處於新建狀態。
2)就緒(Ready):當線程對象調用啓動方法後,該線程處於就緒狀態,線程計入線程隊列排隊,此時該狀態線程並未開始執行,它僅表示可以運行了
3)運行(Running):若處於就緒狀態的線程獲得了CPU,開始執行run()線程執行體,該線程處於執行狀態
4)阻塞(Blocked):線程運行過程中需要被中斷
注意:阻塞狀態不能直接轉成運行狀態,阻塞狀態只能重新進入就緒狀態
線程阻塞的原因:
1>線程(調用sleep方法或wait方法)主動放棄佔用的CPU資源。
2>線程調用了阻塞式的IO方法,在該方法返回前,線程被阻塞。
3>線程訪問臨界資源時,沒有獲取到相關的鎖。
4>線程被掛起。
5)死亡(Terminated):
1>線程正常結束。
2>線程拋出未捕獲的Exception或Error
java中的線程:
創建線程三種方式:
1)繼承Thread類:
1>子類重寫父類中的run方法。
2>建立子類對象的同時線程也被創建。
3>通過調用start方法啓動線程:new MyThread().start();
特點:不能再繼承其他類了,同份資源不共享。
注意:Thread類實現了Runnable接口
2)實現Runnable接口:
1>子類覆蓋接口中的run方法。
2>通過Thread類創建線程,並將實現了Runnable接口的子類對象作爲參數傳遞給Thread類的構造函數。
3>Thread類對象調用start方法啓動線程:
new Thread(new Runnable(){
public void run() {
...
}
}).start();
特點:
1>多個線程共享一個目標資源(即run方法中的內容),適合多線程處理同一份資源。
2>該類還可以繼承其他類,也可以實現其他接口,擴展性較好。
3)實現Callable接口(jdk1.5):
java.util.concurrent包下的Callable接口:
public interface Callable<V> {
V call() throws Exception;
}
Callable和Runnable的區別:
1)Callable定義的方法是call,而Runnable定義的方法是run。
2)Callable的call方法可以有返回值,而Runnable的run方法不能有返回值。
3)Callable的call方法可拋出異常,而Runnable的run方法不能拋出異常。
線程的狀態(生命週期):
java.lang.Thread.State
public enum State {
// Thread state for a thread which has not yet started.
NEW, // 新建狀態
/**
* Thread state for a runnable thread.
* A thread in the runnable state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system such as processor.
* java將操作系統中運行和就緒兩個狀態合併稱爲運行狀態。我們也可以細分一下:
* 就緒狀態:當線程對象調用start()方法後,該線程處於就緒狀態,線程計入線程隊列排隊,此時該線程並未開始執行,它僅表示線程已經準備就緒。
* 運行狀態:若處於就緒狀態的線程獲得了CPU,開始執行run()線程執行體,此時該線程處於運行狀態。
*/
RUNNABLE, // 運行狀態
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock to enter a synchronized block/method or reenter a synchronized block/method after calling {Object.wait}.
* 線程在訪問synchronized修飾的方法或方法塊時,因無法獲得監視器而進入阻塞狀態。或者是線程進入同步方法(同步代碼塊)後調用了Object.wait()方法。
*
* 線程調用了阻塞式的IO方法,在該方法返回前,線程被阻塞。
*/
BLOCKED, // 阻塞狀態
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the following methods:
***** {Object.wait} with no timeout *****
***** {Thread.join} with no timeout *****
***** {LockSupport.park} *****
*
* A thread in the waiting state is waiting for another thread to perform a particular action.
*
* For example, a thread that has called Object.wait() on an object is waiting for another thread to call Object.notify() or Object.notifyAll() on that object.
* A thread that has called Thread.join() is waiting for a specified thread to terminate.
*
* 注意:線程因無法獲取到java.util.concurrent.locks.lock鎖,進入等待狀態,而不是進入阻塞狀態!因爲lock是使用LockSupport的park()方法來實現線程的阻塞。
*/
WAITING, // 等待狀態
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of the following methods with a specified positive waiting time:
* {Thread.sleep}
* {Object.wait} with timeout
* {Thread.join} with timeout
* {LockSupport.parkNanos}
* {LockSupport.parkUntil}
*/
TIMED_WAITING, // 超時等待狀態
/**
* Thread state for a terminated thread.
* 進入死亡狀態的場景:
* 1)run()執行完成,線程正常結束
* 2)線程拋出未捕獲的Exception或Error
* 3)調用線程的stop() (易導致死鎖,不推薦)
* 注意:
* 1)主線程結束後,其他線程不受其影響,不會隨之結束;一旦子線程啓動起來後,就擁有和主線程相等地位,不受主線程影響。
* 2)測試線程是否活着,可用線程對象的isAlive()方法。
* 3)已死亡的線程是不可能通過start()方法喚醒線程的(線程死不能復生),否則引發IllegalThreadStateException異常
*/
TERMINATED; // 死亡狀態(或結束狀態)
}
線程的優先級:
1)每個線程都有優先級,優先級的高低只和線程獲得執行機會的次數多少有關,並非線程優先級越高的就一定先執行,哪個線程的先運行取決於CPU的調度;
2)線程優先級的繼承性:如果A線程啓動B線程,則B線程的優先級與A線程是一樣的。
eg:默認情況下main線程具有普通的優先級,而它創建的線程也具有普通優先級。
3)Thread對象的setPriority(int x)和getPriority()來設置和獲得優先級。
MAX_PRIORITY : 值是10
MIN_PRIORITY : 值是1
NORM_PRIORITY : 值是5(主方法默認優先級)
注意:不能在程序中通過Java線程的優先級來判斷都處於就緒狀態的線程的執行順序。
1>Java的線程是通過映射到操作系統的原生線程上來實現的,故最終的調度還是取決於操作系統。
2>雖然操作系統也提供線程優先級的功能,但是並不能和Java線程的優先級一一對應,Java線程的優先級可能被操作系統改變。
守護線程:
說明:當進程中不存在非守護線程時,守護線程會自動銷燬。
線程安全:
概念:在多線程環境下,一個類在執行某個方法時,對類的實例變量的訪問是安全的(保證原子性+可見性),也就是我們所說的多線程的同步訪問。
避免死鎖:
1)避免一個線程同時獲取多個鎖
2)嘗試使用定時鎖,使用lock.tryLock(timeout)。
3)使用枚舉:枚舉類的構造函數爲私有,不能再創建枚舉對象,枚舉對象的聲明和初始化都是在static塊中,故保證了枚舉類的線程安全。
Java中的線程
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.