### Java 線程的狀態及切換
JDK中線程狀態的定義:
```
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
```
Java線程一共有七個狀態
* 新建(New)
* 就緒(Ready to run)
* 運行中(Running)
* 睡眠(Sleeping)
* 阻塞(Blocked)
* 等待(Waiting)
* 死亡(Dead/Terminate)


## 線程間的狀態轉換
### (1)NEW\(`新建尚未運行/啟動`\)
還沒調用start,或者調用了start\(\)方法,不一定立即改變線程狀態,中間可能需要一些步驟才完成一個線程的啟動。
### (2)RUNNABLE\(`處于可運行狀態:正在運行或準備運行`\)
start調用結束,線程由NEW變成RUNNABLE,存活著,并嘗試占用CPU資源,yield操作時,線程還是Runnable狀態,只是它有一個細節的內部變化,做一個簡單的讓步。在Java層面是Runnable的狀態,并不代表一定處于運行中的狀態,比如BIO中,線程正阻塞在網絡等待的時候,看到的狀態依然是Runnable狀態,而底層線程已經被阻塞住了。
### (3)BLOCKED\(`等待獲取鎖時進入的狀態`\)
線程被掛起了,原因通常是因為它在等待一個鎖,當某個synchronized正好有線程在使用時,一個線程嘗試進入這個臨界區,就會被阻塞,直到另一個線程走完臨界區或發生了相應鎖對象的wait操作后,它才有機會去爭奪進入臨界區的權利。當搶到鎖之后,才會從blocked狀態恢復到runnable狀態。這個狀態它好像什么也不做一樣。
### (4)WAITING\(`通過wait方法進入的等待`\)
當調用一下wait,join,park方法調用時,進入waiting狀態。前提是這個線程已經擁有鎖了。
> blocked和waiting狀態的區別是:
> A、blocked是虛擬機認為程序還不能進入某個區域,因為同時進去就會有問題,這是一塊臨界區。
> B、發生wait等操作的先決條件是要進入臨界區,也就是線程已經拿到鎖了,自己可能進去做了一些事情,但此時通過判定業務上的參數,發現還有一些其他配合的資源沒有準備充分,那么自己就等等再做其他事情。
在waiting狀態下,如果發生了interrupt操作,則處于該狀態的線程在內部會拋出一個InterruptedException,這個異常應當在run方法內捕獲,使得run方法正常地執行完成,當然捕獲異常后,是決定讓線程繼續運行,還是結束等要根據業務場景才處理。
如果發生了notify動作,則會從等待池當中喚醒一個線程重新恢復到Runnable狀態,如果是notifyall操作,則喚醒所有等待線程。
### (5)TIMED\_WAITING\(`通過sleep或wait timeout方法進入的限期等待的狀態`\)
通過wait\(t\),sleep\(t\),join\(t\),parkNanos,parkUntil等方法進入此狀態。當時間達到時觸發線程回到工作狀態Runnable。
interrupt只對處于waiting或timed\_waiting狀態的線程起作用,對其他狀態不起作用。
### (6)TERMINATED\(`線程終止狀態`\)
線程結束了,就處于這種狀態,也就是run方法運行完了。這只是Java語言級別的一種狀態,在操作系統內部可能已經注銷了相應的線程,或者將它復用給其他需要使用線程的請求。
### 總結
* JAVA中的RUNNABLE狀態并不代表它一定處于運行中狀態,如在BIO中線程正阻塞在網絡等待時,看到的狀態依然是RUNNABLE狀態,而底層線程已被阻塞,這也是JAVA內在一些狀態不協調的問題所在
參考資料:
[https://segmentfault.com/a/1190000005006079](https://segmentfault.com/a/1190000005006079)
- 簡介
- 概述
- 進程vs線程
- 資源限制
- 有關并行的兩個定律
- 線程同步和阻塞
- 線程阻塞
- 線程的特性
- 守護線程
- 線程異常
- Thread
- 線程狀態
- 線程中斷
- wait¬ify
- suspend&resume
- join&yield
- notify¬ifyAll
- Thread.sleep
- 線程任務
- Runnable
- Callable
- Future模式
- FutureTask
- 線程實現方式
- 內核線程實現
- 用戶線程實現
- 混合實現
- Java線程的實現
- java與協程
- 纖程-Fiber
- 線程調度
- 多線程協作方式
- 阻塞
- 放棄
- 休眠
- 連接線程
- 線程估算公式
- 線程活躍性
- 死鎖
- 線程安全性
- 對象的發布與逸出
- 構造方法溢出
- 線程封閉
- 對象的可變性
- 原子性
- 原子操作
- CPU原子操作原理
- 總線鎖
- 緩存鎖
- JAVA如何實現原子操作
- long和double讀寫操作原子性
- Adder和Accumulator
- 線程性能
- 同步工具類
- 閉鎖
- CountDownLatch
- FutureTask
- 信號量
- 柵欄
- CyclicBarrier
- Exchanger
- 并發編程
- volatile
- synchronized
- 無鎖
- 偏向鎖
- 輕量級鎖
- 鎖的優缺點對比
- 鎖升級
- 鎖消除
- Monitor
- synchronized語法
- Mutex Lock
- synchronized實踐問題
- synchronized&ReentrantLock
- Lock
- ReentrantLock
- Condition
- 讀寫鎖
- ReadWriteLock
- StampedLock
- 線程池
- Executor
- ExecutorService
- Executors
- ThreadPoolExecutor
- RejectedExecutionHandler
- ThreadFactory
- 線程池大小公式
- 動態調整線程池大小
- Fork/Join框架
- ForkJoinPool
- CompletableFuture
- JUC并發工具包
- LockSupport
- 延時任務與周期任務
- Timer
- TimerTask
- 異構任務并行化
- CompletionService
- volatile和synchronized比較
- 鎖優化
- 鎖相關概念
- 悲觀鎖(排它鎖)
- 樂觀鎖
- 自旋鎖
- 樂觀鎖vs悲觀鎖
- JVM鎖優化-鎖消除
- ThreadLocal
- InheritableThreadLocal
- TransmittableThreadLocal
- ThreadLocalRandom
- 無鎖
- AtomicInteger
- Unsafe
- AtomicReference
- AtomicStampedReference
- AtomicIntegerArray
- AtomicIntegerFieldUpdater
- 無鎖Vector
- LongAdder
- LongAccumulator
- 常見鎖類型
- 悲觀鎖&獨占鎖
- 樂觀鎖
- 樂觀鎖vs悲觀鎖
- 自旋鎖vs適應性自旋鎖
- 公平鎖vs非公平鎖
- 可重入鎖vs非可重入鎖
- 獨享鎖vs共享鎖
- 互斥鎖
- CAS
- AQS介紹
- AQS深入剖析
- AQS框架
- AQS核心思想
- AQS數據結構
- 同步狀態State
- ReentrantLock vs AQS
- AQS與ReentrantLock的關聯
- ReentrantLock具體實現
- 線程加入等待隊列
- 等待隊列中線程出隊列時機
- 如何解鎖
- 中斷恢復后的執行流程
- ReentrantLock的可重入應用
- JUC中的應用場景
- 自定義同步工具
- CLH鎖
- 并發框架
- Akka
- Disruptor-無鎖緩存框架
- 常見面試題
- 兩個線程交替打印A和B
- 附錄