Java併發與鎖設計實現詳述(1)- Java執行緒狀態
從這篇文章開始,我們正式進入Java併發與鎖的世界。
何為併發?何為鎖?在Java中一般都是以執行緒為單位執行任務的,當多個執行緒在執行任務過程中在同一時間對某個共享資源進行訪問時,我們稱這種現象為併發,而為了保證多個執行緒在併發獲取這個共享資源的時候不會出現狀態不一致的問題或者相互影響,需要對這個共享資源進行限制,只有通過這個限制的執行緒才能獲取到這個共享資源的控制和操作權,而鎖就是對資源的限制,得到了鎖才能對鎖包裝的資源進行訪問。
對鎖的競爭牽涉到執行緒的狀態切換,因此,在這裡,我們首先需要知道在Java中執行緒都有哪些狀態,這些狀態之間又是怎麼切換的。
我們首先來看下在JDK1.7中對於執行緒狀態的定義,可以在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. */ 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 * {@link Object#wait() Object.wait}. */ BLOCKED, /** * Thread state for a waiting thread. * A thread is in the waiting state due to calling one of the * following methods: * <ul> * <li>{@link Object#wait() Object.wait} with no timeout</li> * <li>{@link #join() Thread.join} with no timeout</li> * <li>{@link LockSupport#park() LockSupport.park}</li> * </ul> * * <p>A thread in the waiting state is waiting for another thread to * perform a particular action. * * For example, a thread that has called <tt>Object.wait()</tt> * on an object is waiting for another thread to call * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on * that object. A thread that has called <tt>Thread.join()</tt> * is waiting for a specified thread to terminate. */ 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: * <ul> * <li>{@link #sleep Thread.sleep}</li> * <li>{@link Object#wait(long) Object.wait} with timeout</li> * <li>{@link #join(long) Thread.join} with timeout</li> * <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li> * <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li> * </ul> */ TIMED_WAITING, /** * Thread state for a terminated thread. * The thread has completed execution. */ TERMINATED; }
從這個列舉中,我們可以看到分為NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED七種狀態。這裡在分析時我只選擇比較重要和關鍵的狀態進行分析。
執行緒之間的狀態切換如下圖所示:
下面對各種執行緒狀態進行一些說明。
(1)新建狀態(初始狀態)
實現Runnable介面或者繼承Thread的類便可以得到一個執行緒類,如果是實現Runnable介面的類,那麼還需要將這個類作為引數傳遞給Thread類才可以作為執行緒啟動。
(2)可執行狀態
當新建狀態的執行緒呼叫start()方法後便進入了可執行狀態。進入可執行狀態只是說明執行緒有機會進入執行狀態,只有得到了執行的時間片才能真正得到執行並進入執行狀態。
當時間片用完後或者呼叫yield()方法,執行中的執行緒會進入可執行狀態。
對於鎖池中的執行緒,如果拿到了鎖,會重新進入可執行狀態。
(3)執行狀態
執行緒排程會從可執行執行緒池中根據一定的規則選擇一個執行緒給其分配時間片進行執行,這也是進入執行狀態的唯一方式。
(4)結束(終止)狀態
當執行緒執行run()方法結束後或者主執行緒終止後,執行緒就會進入終止狀態,當然如果線上程執行過程中如果遇到了異常也會進入終止狀態。在一個終止的執行緒上呼叫start()方法,會丟擲java.lang.IllegalThreadStateException異常。
(5)阻塞狀態
當正在執行的執行緒如果(a)需要等到其他資源就緒(b)呼叫Thread.sleep()方法休眠一段時間(c)執行在該執行緒中的其他執行緒呼叫join()方法,那麼當前執行緒都會進入阻塞狀態。處於阻塞狀態的執行緒,如果遇到(a)等待的資源已經就緒(b)休眠的時間已經到了(c)呼叫join()的其他執行緒已經結束,則此時當前執行緒會進入可執行狀態。
(6)鎖池狀態
噹噹前執行緒如果去競爭一個鎖而這個鎖被其他執行緒獲取了,則此時當前執行緒進入鎖池狀態。
(7)等待佇列
呼叫obj的wait(), notify()方法前,必須獲得obj鎖,也就是必須寫在synchronized(obj) 程式碼段內。當呼叫wait()方法時當前執行緒會釋放當前獲取的鎖,並將當前執行緒移入等待佇列。當其他執行緒呼叫這個obj的notify()或者notifyAll()方法時,當前執行緒會被通知並進入到鎖池中。
與等待佇列相關的操作步驟和圖說明如下:
至此,Java中的執行緒狀態及狀態之間的切換便大致講述完了,謝謝。