只要涉及到線程,其運行結果就是不確定的,雖然說java很早就提供了線程以及併發的支持,但是我們需要知道,線程是完全交給調度器的。有很多同學在編寫書上的代碼時,會發現運行結果不一致,其實這不是書上的例子錯了,而是運行環境不一致導致的(cpu核數).
而接下來的所涉及到到線程,指的是語言層次的線程,而不是操作系統層次的。
1. Java語言中線程的實現
從JDK 1.2 開始,JVM中的線程模型替換爲了基於操作系統原生線程模型來實現的,因此,操作系統支持怎樣的線程模型,很大程度上決定了JVM的線程模型。
在Java語言中,提供了兩種實現線程的方式,Thread類和Runnable接口。對於怎麼使用,這裏就不說了。
2. Java線程調度
線程調度是指系統爲線程分配處理器使用權的過程,主要調度方式有兩種:協同式線程調度,搶佔式線程調度。
有的朋友可能會說,Java的線程調度方式是搶佔式的。通過線程模型的實現可以知道,在JDK1.2之後,線程模型很大程度上取決與操作系統。而Java中的線程調度就是搶佔式調度。
2.1 協同式調度
線程的執行時間完全由線程本身決定,線程執行完畢纔會通知系統進行線程切換。
- 優點
- 實現簡單
- 缺點
- 線程執行時間不可控
2.2 搶佔式調度
線程的執行時間由系統來分配,線程切換不由線程本身決定
- 優點
- 系統可控
2.2.1 優先級調度
雖然我們可以設置優先級,建議系統給線程分配更多的時間,但是,這是不可靠的。因爲線程調度最終還是取決於操作系統。通過Thread.yield()方法可以讓出執行時間,讓優先級更高的線程先執行。
3. 狀態轉換
- 新建狀態(new) 創建後尚未啓動的線程
- 運行狀態(Runnable) 注意:這裏的線程可能正在運行,也可能在等待CPU分配時間片段
- 等待狀態
- 無限期等待(Waiting) 這種狀態不會被分配時間片段,需要被喚醒
- 沒設置時間(無期限)Object.wait()方法 |
- 沒設置時間(無期限)Thread.join()方法
- LockSupport.park()方法
- 期限等待(Timed Waiting) 等待一段時間後,就可以被分配時間片段
- Thread.sleep()
- 設置了時間的Object.wait()
- 設置了事件的Thread.join()
- LockSupport.parkNanos()
- LockSupport.parkUntil()
- 無限期等待(Waiting) 這種狀態不會被分配時間片段,需要被喚醒
- 阻塞(blocked) 等待獲取鎖
- 結束狀態(Terminated) 線程執行完畢,終止線程的線程狀態。
4.如何回收線程
回收線程防止內存泄露。一般來說如下
Thread.interrupt() //產生中斷
Thread.join() //等待死亡
參考資料
- 深入理解Java虛擬機
- Java 線程詳解