/**
* @since 2022/9/8 19:26
* @author monk
*/
class MyThread :Thread(){
override fun run() {
println("当前线程:${currentThread().toString()}")
}
}
fun main() {
val myThread = MyThread()
myThread.start()
println("当前线程:${Thread.currentThread().toString()}")
}
/**
* 结果:
* 当前线程:Thread[main,5,main]
* 当前线程:Thread[Thread-0,5,main]
*/
class MyRunnable :Runnable{
override fun run() {
println("子线程:${Thread.currentThread()}")
}
}
fun main() {
val myRunnable = MyRunnable()
Thread(myRunnable).start()
println("主线程:${Thread.currentThread()}")
}
/**
* 结果:
* 主线程:Thread[main,5,main]
* 子线程:Thread[Thread-0,5,main]
*/
class MyCallable<String> : Callable<kotlin.String> {
override fun call(): kotlin.String {
return "子线程:${Thread.currentThread()}"
}
}
fun main() {
val myCallable = MyCallable<String>()
val singleThread = Executors.newSingleThreadExecutor()
val submit = singleThread.submit(myCallable)
println(try {
submit.get()
} catch (e: Exception) {
e.printStackTrace()
} finally {
singleThread.shutdown()
})
println("主线程:${Thread.currentThread()}")
}
/**
* 结果:
* 子线程:Thread[pool-1-thread-1,5,main]
* 主线程:Thread[main,5,main]
*/
参考《参考《深入理解Java虚拟机》Java与线程-状态转换》
Java语言定义了5中进程状态,在任意一个时间点中,一个进程只能有且只有其中一种状态,这5中状态分别是:
新建(New):创建后尚未启动的线程处于这种状态
运行(Runable):包括操作系统线程状态中的Running 和 Ready,也就是处于此状态的线程有可能正在执行,也有可能正在等待着CPU为它分配执行时间
无限期等待(Waiting):处于这种状态的进程不会被分配CPU执行时间,它们要等待被其它线程显示地唤醒,以下方法会让线程陷入无限期等待状态:
限期等待(Timed Waitting):处于这种状态的进程也不会被分配CPU执行时间,不过无须等待被其他线程显示地唤醒,在一定时间之后它们会由系统自动唤醒
阻塞(Blocked):进程被阻塞了,“阻塞状态”与“等待状态”的区别是:“阻塞状态”在等待着获取到一个排它锁,这个事件将在另外一个线程放弃这个锁的时候发生:而“等待状态”则是在等待一段时间,或者唤醒动作的发生。在程序等待进入同步区域的时候,线程将进入这种状态。
结束(Terminated):已终止线程的线程状态,线程已经结束执行。
布尔值标记
的运用,以往有的时候会使用stop()方法来停止线程,但现在的JDK早就废除了stop()方法,不建议使用,现在提倡在run()方法中使用无限循环的形式,然后使用一个布尔型标记控制循环的停止class MyRunnable : Runnable {
var flag = true
override fun run() {
var i = 0
while (flag) {
Thread.sleep(500)
println("i:${i++}")
}
println("终止了")
}
fun close() {
flag = false
}
}
fun main() {
val myRunnable = MyRunnable()
Thread(myRunnable).start()
Thread.sleep(5000)
myRunnable.close()
}
/*
i:0
i:1
i:2
i:3
i:4
i:5
i:6
i:7
i:8
i:9
终止了
*/
interrupt()
方法,如果线程使用sleep()或wait()方法进入了就绪状态,那么可以使用interrupt()方法是线程离开run()方法,同时结束线程,但会抛InterruptedException异常,用户可以在处理异常时完成线程的中断业务处理,如终止while循环class MyRunnable : Runnable {
var flag = true
override fun run() {
var i = 0
while (flag) {
try {
Thread.sleep(500)
} catch (e: Exception) {
flag = false
}
println("i:${i++}")
}
println("终止了")
}
}
fun main() {
val myRunnable = MyRunnable()
val thread = Thread(myRunnable)
thread.start()
Thread.sleep(5000)
thread.interrupt()
}
/*
i:0
i:1
i:2
i:3
i:4
i:5
i:6
i:7
i:8
i:9
终止了
*/
在 Java 中,使用 Object.wait()/Object.wait(long) 和 Object.notify()/Object.notifyAll() 可以用于实现等待和通知。用法省略。
原理:
JVM 会给每个对象维护一个入口集(Entry Set)和等待集(Wait Set)。
入口集用于存储申请该对象内部锁的线程,等待集用于存储对象上的等待线程。
wait() 方法会将当前线程暂停,在释放内部锁时,会将当前线程存入该方法所属的对象等待集中。
调用对象的 notify() 方法,会让该对象的等待集中的任意一个线程唤醒,被唤醒的线程会继续留在对象的等待集中,直到该线程再次持有对应的内部锁时,wait() 方法就会把当前线程从对象的等待集中移除。
添加当前线程到等待集、暂停当前线程、释放锁以及把唤醒后的线程从对象的等待集中移除,都是在 wait() 方法中实现的。
在 wait() 方法的 native 代码中,会判断线程是否持有当前对象的内部锁,如果没有的话,就会报非法监视器状态异常,这也就是为什么要在同步代码块中执行 wait() 方法。
wait()/notify() 过于底层,而且还存在两个问题,一是过早唤醒、二是无法区分 Object.wait(ms) 返回是由于等待超时还是被通知线程唤醒。
使用 await/signal 协作方式有下面几个要点。
基本用法:
class AwaitSignal {
private val lock: Lock = ReentrantLock()
private val condition: Condition = lock.newCondition()
@Volatile
private var conditionSatisfied = false
fun startWait() {
lock.lock()
println("等待线程获取了锁")
try {
while (!conditionSatisfied) {
println("保护条件不成立,等待线程进入等待状态")
condition.await()
}
println("等待线程被唤醒,开始执行目标动作")
} catch (e: InterruptedException) {
e.printStackTrace()
} finally {
lock.unlock()
println("等待线程释放了锁")
}
}
fun startNotify() {
lock.lock()
println("通知线程获取了锁")
try {
conditionSatisfied = true
println("通知线程即将唤醒等待线程")
condition.signal()
} finally {
println("通知线程释放了锁")
lock.unlock()
}
}
}
fun main() {
val awaitSignal = AwaitSignal()
thread {
awaitSignal.startWait()
}
thread {
awaitSignal.startNotify()
}
}
/*
等待线程获取了锁
保护条件不成立,等待线程进入等待状态
通知线程获取了锁
通知线程即将唤醒等待线程
通知线程释放了锁
等待线程被唤醒,开始执行目标动作
等待线程释放了锁
*/
LockSupport
是一个线程阻塞工具类,所有的方法都是静态方法,可以让线程在任意位置阻塞,当然阻塞之后肯定得有唤醒的方法,主要有两类方法:park
和unpark
,另外线程中断的方法也能解除park
阻塞状态
class LockSupportS :Runnable{
var u = Any()
override fun run() {
synchronized(u) {
println("in ${Thread.currentThread().name}")
LockSupport.park()
if (Thread.currentThread().isInterrupted) {
println("被中断了")
}
println("继续执行")
}
}
}
fun main() {
val lockSupport = LockSupportS()
val t1 = Thread(lockSupport, "t1")
t1.start()
Thread.sleep(1000)
val t2 = Thread(lockSupport, "t2")
t2.start()
Thread.sleep(1000)
// t1.interrupt()
LockSupport.unpark(t1)
LockSupport.unpark(t2)
}
/*
in t1
继续执行
in t2
继续执行
*/