-
概述
- Java 線程偏向於 時間片 的操作
-
背景
-
之前了解 圍繞監視器鎖 的一些線程操作
- synchronized
- wait(), notify(), notifyAll()
-
但是還有別的問題, 沒有覆蓋到
-
問題
- 我想讓我的線程 在不釋放鎖 的情況下, 停止一段時間
- 我想讓我的線程, 放棄現在的 時間片
- 我想讓我的線程, 排在別的線程之后
-
這些問題, 光靠 監視器鎖, 好像解決不了
- 沒關系, 我們還有別的工具
-
1. 睡眠
-
概述
- 線程暫停
-
場景: 輪詢
- 問題
-
線程輪詢時, 如果一直高頻率詢問, 會有弊端
- 高頻詢問消耗 cpu 資源
- 高頻詢問, 很多次詢問, 都是無效的
-
解決
- 一次輪詢失敗后, 休息一段時間, 再嘗試下一次輪詢
-
- 問題
-
sleep()
-
概述
- 讓當前線程, 停止一段時間, 然后繼續
-
解釋
-
當前線程
- 只能給 當前線程 使用
- 源碼注釋
- static 方法
- 只能給 當前線程 使用
-
停止
- 具體機制
- 將當前線程轉換到 wait 狀態
- 線程狀態?
- 不執行任何代碼
- 消耗最少的資源
- 等待 調度器 喚醒
- 線程狀態?
- 將當前線程轉換到 wait 狀態
- 具體機制
-
一段時間
- 單位
- ms
- 定義
- 時間是由 調用者 設定的
- 單位
-
繼續
- 繼續上次的執行
- 從 sleep 下一句開始
- 繼續上次的執行
-
-
-
問題
- sleep 的時間, 可能會不准確
-
狀態
- sleep 被喚醒后, 是 可執行狀態
- 可執行 到 執行中, 會有一個 時間
-
線程調度
- sleep 從 wait 到 被喚醒, 到 分配到時間片執行, 中間需要若干個 線程調度 的步驟
- 不同的 jvm 實現, 可能會有所差異
-
誤差
- 誤差通常在 10ms 左右吧
-
- sleep 的時間, 可能會不准確
-
注意
-
sleep 不會對鎖有影響
- 可以在 同步/非同步 代碼里執行
- sleep 不會改變鎖的 持有情況
-
sleep 如果被打斷, 會拋出異常
- InterruptedException
- 這個后續再說
-
2. 讓步
-
概述
- 讓步
-
場景: ...
- 尷尬了
- 老實說, 我也不知道這有什么場景
- 源碼里提到, 這個方法在 java.util.concurrent.locks 的代碼測試中有過使用
- 作用
- 收回當前線程的 時間片, 讓線程重新回到 runable 階段
- 重新開展 線程調度
- 尷尬了
-
yield()
-
概述
- 讓當前線程, 讓出 cpu 時間片
-
解釋
-
當前線程
- 同 sleep
-
讓出 cpu 世間片
- 線程的執行, 需要 cpu時間片
- 讓出 cpu時間片, 則 線程不再執行
- 通常線程會回到 runable 階段, 重新參與調度
-
-
-
注意
- 可能會被部分 jvm 忽略
- yield 不會對鎖 有影響
- 同 sleep
3. 合成
-
概述
- 合成
-
場景: 先后執行
-
先后執行
- 線程T1 需要等待 線程T2 的執行結果
- 線程T1 持有 線程T2 的引用
-
疑問
- 為啥不用 監視器鎖
- 有些代碼實現, 沒有用 synchronized, 我想等這塊的東西, 但又不想改代碼
- 為啥不用 監視器鎖
-
-
join()
-
概述
- 等待其他線程執行結束, 然后繼續
-
解釋
-
等待
- 保持 wait 狀態
- 持續執行 wait 方法
- 機制
- T1 執行 T2 的 join 方法
- 帶時間參數的 join, 竟然是 同步方法
- T1 獲得 T2 的 鎖
- 沒錯, 是 線程T2 對應 Thread 對象的鎖
- 這個 通常 不會影響 T2 正在執行的任務
- 但是如果真的被阻塞了, 確實需要等在那里
- T1 開始循環, 判斷 T2 是否存活
- 如果 T2 存活, 則一直 wait()
- wait() 就意味着鎖...
- 如果 T2 存活, 則一直 wait()
- T1 執行 T2 的 join 方法
- 保持 wait 狀態
-
其他線程
- join 需要持有其他線程的引用
-
繼續
- join 回來后, 從 wait 后面的代碼開始, 繼續執行
-
-
-
問題: 抱歉, 這倆問題, 我現在無法解答
-
T1 在 wait 階段, T2 還活着, T1 是怎么被喚醒的
-
同步方法是不是意味着, 只能有一個 T2 的 join, 只能被一個線程調用
- 如果多個線程調用 wait, 會是怎樣一種請情況
-
T2 線程如果出現了異常, T1 會是怎么樣一種反應?
-
-
注意
- join 途中, 如果被打斷, T1 會拋出異常
- InterruptedException
- 怎么又是你
- InterruptedException
- join 途中, 如果被打斷, T1 會拋出異常
4. 后續
-
線程狀態
- 說了這么線程相關的方法, 終於該說這個線程狀態了
- 之前想嘗試先講狀態, 但是寫了點發現越寫越難寫
- 說了這么線程相關的方法, 終於該說這個線程狀態了
-
Java 內存模型
- Java 內存模型, 其實很復雜
-
多線程
- 終於到這一步了...
ps
- ref
- Java 語言規范(SE 8th)
- Java Thread sleep
- 簡單清晰
- Java 核心技術(10th editon) 卷1
- Java多線程中join方法的理解
- 講得挺好
- 作者后來還成了 攜程某部門的 CTO, 還創立了 優知學院, 挺厲害的