一、線程生命週期圖
二、關鍵字講解
-
1)、yield()
yield()方法:使當前線程讓出 CPU 佔有權,但讓出的時間是不可設定的。也不會釋放鎖資源。注意:並不是每個線程都需要這個鎖的,而且執行 yield( )的線程不一定就會持有鎖,我們完全可以在釋放鎖後再調用 yield 方法。
所有執行 yield()的線程有可能在進入到就緒狀態後會被操作系統再次選中馬上又被執行。
yield():使當前的線程釋放時間片,然後進入就緒狀態,不會釋放鎖。
2)、join 方法
把指定的線程加入到當前線程,可以將兩個交替執行的線程合併爲順序執行。
比如在線程 B 中調用了線程 A 的 Join()方法,直到線程 A 執行完畢後,纔會繼續執行線程 B。3)、wait()
實線程進入阻塞狀態,並釋放線程鎖
。並等待其他線程notify()/notifyAll()喚醒。4)、notify()/notifyAll()
喚醒有wait()進入阻塞狀態的線程,是線程進入就緒狀態然後得到CPU分配的時間片就可以進入運行態。
注意:notify()/notifyAll()不會釋放鎖
5)、sleep()
是線程休息一定的時間進阻塞狀態,當時間到時進入就緒狀態,然後等待CPU分配時間片。
注意:sleep()不會釋放鎖
6)、interrupt()
安全的中止則是其他線程通過調用某個線程 A 的 interrupt()
方法對其進行中 斷操作, 中斷好比其他線程對該線程打了個招呼,“A,你要中斷了”,不代表 線程 A 會立即停止自己的工作,同樣的 A 線程完全可以不理會這種中斷請求。 因爲 java 裏的線程是協作式的,不是搶佔式的。線程通過檢查自身的中斷標誌 位是否被置爲 true 來進行響應。
線程通過方法 isInterrupted()
來進行判斷是否被中斷,也可以調用靜態方法 Thread.interrupted()
來進行判斷當前線程是否被中斷,不過 Thread.interrupted() 會同時將中斷標識位改寫爲 false。
如果一個線程處於了阻塞狀態(如線程調用了 thread.sleep、thread.join、 thread.wait 等),則在線程在檢查中斷標示時如果發現中斷標示爲 true,則會在 這些阻塞方法調用處拋出 InterruptedException 異常,並且在拋出異常後會立即 將線程的中斷標示位清除,即重新設置爲 false。
不建議自定義一個取消標誌位來中止線程的運行
。因爲 run 方法裏有阻塞調 用時會無法很快檢測到取消標誌,線程必須從阻塞調用返回後,纔會檢查這個取 消標誌。這種情況下,使用中斷會更好,因爲:
- 一、一般的阻塞方法,如 sleep 等本身就支持中斷的檢查,
- 二、檢查中斷位的狀態和檢查取消標誌位沒什麼區別,用中斷位的狀態還可 以避免聲明取消標誌位,減少資源的消耗。
注意:處於死鎖狀態的線程無法被中斷
三、生產者和消費着模式
1)、wait(),notify()和notifyAll()實現
wait
等待時釋放synchronized
鎖;notify
和notifyAll
不釋放synchronized
鎖,一般寫在最後。
倉庫
class Storage {
//Kotlin中的每個類都繼承自Any,但Any不聲明wait(),notify()和notifyAll()
// 但仍然可以使用java.lang.Object的一個實例作爲鎖,並調用它的方法。
private val lock = Object()
val list: LinkedList<Any> = LinkedList()
//生產者
fun produce() = synchronized(lock) {
while (list.size > MAX_NUM) {
try {
println("【生產者" + Thread.currentThread().name + "】倉庫已滿")
lock.wait()
} catch (e: Exception) {
e.printStackTrace()
}
}
list.add(Any())
println("【生產者" + Thread.currentThread().name + "】生產一個產品,現庫存" + list.size)
lock.notifyAll()
}
//消費者
fun consume() = synchronized(lock) {
while (list.size == 0) {
try {
println("【消費者" + Thread.currentThread().name + "】倉庫爲空")
lock.wait()
} catch (e: Exception) {
e.printStackTrace()
}
}
list.remove()
println("【消費者" + Thread.currentThread().name + "】消費一個產品,現庫存" + list.size)
lock.notifyAll()
}
companion object {
const val MAX_NUM = 2
}
}
生產者
class Producer : Runnable {
var storage: Storage
constructor(storage: Storage) {
this.storage = storage
}
override fun run() {
while (true) {
try {
Thread.sleep(300)
storage.produce()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
消費者
class Consumer : Runnable {
var storage: Storage
constructor(storage: Storage) {
this.storage = storage
}
override fun run() {
while (true) {
try {
Thread.sleep(300)
storage.consume()
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
調用
object TestMain {
@JvmStatic
fun main(argc: Array<String>) {
val storage = Storage()
for (i in 0..4) {
Thread(Producer(storage)).start()
}
for (i in 0..4) {
Thread(Consumer(storage)).start()
}
}
}
2)、ArrayBlockingQueue實現
class LinkBlockQueueText {
@Volatile //kotlin沒有volatile關鍵字,的用註解形式實現
var blockQueue: ArrayBlockingQueue<Any> = ArrayBlockingQueue(3)
fun producer() {
try {
blockQueue.put(Any())
println("【生產者" + Thread.currentThread().name
+ "】生產一個產品,現庫存" + blockQueue.size)
} catch (e: Exception) {
e.printStackTrace()
}
}
fun consumer() {
try {
blockQueue.take()
println("【消費者" + Thread.currentThread().name
+ "】消費了一個產品,現庫存" + blockQueue.size)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
object TestMain {
@JvmStatic
fun main(argc: Array<String>) {
val linkedQueue = LinkBlockQueueText()
Thread(Runnable {
for (i in 0 until 5) {
Thread.sleep(500)
linkedQueue.producer()
}
}).start()
Thread(Runnable {
for (i in 0 until 5) {
Thread.sleep(300)
linkedQueue.consumer()
}
}).start()
}
}
put()
方法:類似於我們上面的生產者線程,容量達到最大時,自動阻塞。
take()
方法:類似於我們上面的消費者線程,容量爲0時,自動阻塞。