Java并發編程系列之一:Thread簡介
線程的概述
線程是一個程序的多個執行路徑,執行調度的單位,依托于進程存在。 線程不僅可以共享進程的內存,而且還擁有一個屬于自己的內存空間,這段內存空間也叫做線程棧,是在建立線程時由系統分配的,主要用來保存線程內部所使用的數據,如線程執行函數中所定義的變量。
注意:Java中的多線程是一種搶占機制而不是分時機制。搶占機制指的是有多個線程處于可運行狀態,但是一個CPU同時只允許一個線程在運行,他們通過競爭的方式搶占CPU。
線程的狀態
NEW(新建狀態):當一個線程的實例被創建即使用new關鍵字和Thread類或其子類創建一個線程對象后,此時該線程處于新生(new)狀態,處于新生狀態的線程有自己的內存空間,但該線程并沒有運行,此時線程還不是活著的
RUNNABLE(就緒狀態):當一個新建的線程執行Thread.start()以后,線程進入就緒狀態。這個狀態的線程已經做好了運行的準備工作,但是還沒有真正執行run方法的代碼。
RUNNING(運行中):當一個就緒狀態的線程,被CPU選中,分配時間片開始執行,就進入到運行中狀態。這個狀態的線程已經在真正執行run方法。
BLOCKED(阻塞狀態):一個運行中的線程,有兩種情況會進入阻塞狀態。一個是等待獲取synchronized鎖的時候;另外一個是一個獲取到synchronized鎖的線程調用Object.wait方法后被喚醒,會進入阻塞狀態,因為它需要重新獲取之前已經得到的鎖。該狀態下的線程,在取到鎖以后,進入就緒狀態。
WAITING(等待狀態):一個運行中的線程,執行Object.wait()、Thread.join()、LockSupport.park()等方法就會進入等待狀態。等待狀態的線程,需要被其他線程喚醒(Object.notifyAll()、LockSupport.unpark()),喚醒以后進入就緒狀態。
TIMED_WAITING(等待一定時間狀態):一個運行中的線程,執行Thread.sleep(timeout)、Object.wait(timeout)、Thread.join(timeout)、LockSupport.parkNanos(timeout)、LockSupport.parkUntil(timeout)等方法進入到等待一定時間狀態。這個狀態的線程,在等待超時或者被其他線程喚醒后,進入到就緒狀態。
TERMINATED(終止狀態):一個線程執行完畢或者被異常中斷以后進入該狀態,該狀態下isAlive方法返回false。
常用方法
- start方法
start()用來啟動一個線程,當調用start方法后,系統才會開啟一個新的線程來執行用戶定義的子任務,在這個過程中,會為相應的線程分配需要的資源。
- run方法
run()方法是不需要用戶來調用的,當通過start方法啟動一個線程之后,當線程獲得了CPU執行時間,便進入run方法體去執行具體的任務。
- sleep方法
sleep相當于讓線程睡眠,交出CPU,讓CPU去執行其他的任務。需要注意的是,sleep方法不會釋放鎖,也就是說如果當前線程持有對某個對象的鎖,在sleep生效期間,其他線程是無法獲取該對象的synchronized鎖。
- yield方法
調用yield方法會讓當前線程交出CPU權限,讓CPU去執行其他的線程。它跟sleep方法類似,同樣不會釋放鎖。但是yield不能控制具體的交出CPU的時間,另外,yield方法只能讓擁有相同優先級的線程有獲取CPU執行時間的機會。yield方法讓線程從RUNNING狀態回到RUNNABLE狀態。
- join方法
A線程執行B線程的join方法以后,A線程需要等B線程執行完成以后才能繼續執行。從狀態角度來講,A線程在執行B線程的join方法以后,A線程進入到WAITING或者TIMED_WAITING狀態,一直等到B線程進入到TERMINATED狀態或者等待超時以后,A線程才會回到RUNNABLE狀態。
- wait方法
wait方法是Object類就實現的方法,線程執行該方法以后,進入到WAITING或者TIMED_WAITING狀態,在被其他線程喚醒或者等待超時后,進入到RUNNABLE狀態。需要注意的是,調用wait方法會釋放已經獲取到鎖,等線程被喚醒以后會進入到BLOCKED狀態。直到重新拿到鎖以后,才會進入到RUNNABLE狀態。
- notify/notifyAll方法
notify/notifyAll方法也是Object類就實現的方法,執行該方法以后,可以喚醒等待隊列里面一個/全部線程,讓他們進入到RUNNABLE狀態。