一、线程生命周期图
Java里面把运行态和就绪态合二为一,操作系统把他们更细的划分。
二、关键字讲解
-
1)、yield()
yield()方法:使当前线程让出 CPU 占有权,但让出的时间是不可设定的。也不会释放锁资源。注意:并不是每个线程都需要这个锁的,而且执行 yield( )的线程不一定就会持有锁,我们完全可以在释放锁后再调用 yield 方法。
所有执行 yield()的线程有可能在进入到就绪状态后会被操作系统再次选中马上又被执行。
yield():使当前的线程释放时间片,然后进入就绪状态,不会释放锁。
2)、join 方法
把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行。
比如在线程 B 中调用了线程 A 的 Join()方法,直到线程 A 执行完毕后,才会继续执行线程 B。3)、wait()
实线程进入阻塞状态,并释放线程锁
。并等待其他线程notify()/notifyAll()唤醒。是Object里面的方法。4)、notify()/notifyAll()
唤醒有wait()进入阻塞状态的线程,是线程进入就绪状态然后得到CPU分配的时间片就可以进入运行态。是Object里面的方法。
注意: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时,自动阻塞。