面试经常性问到要求手写线程交替打印奇偶数,其实就是考察对线程的灵活控制,本次就用2种方式交替打印奇偶数。并且比较下2中方式的效率
第一种:无限循环等待
0. 原理
A线程由于竞争可能造成活锁情况,但是状态会被B线程的运行打破,当B线程执行i++
操作后,i
就会由奇数变成偶数,或者由偶数变成奇数,此时A线程的运行条件就满足了,运行得以持续。
1. 创建运行函数
const val final = 100000 // 截止的数字
var i = 0 // 自增的数字
val lock = Object() // 锁
fun main() {
val start = System.currentTimeMillis()
thread { printOdd(start) }
thread { printEven(start) }
}
2. 两个线程交替打印数字
fun printOdd(start:Long) {
while (i < final) {
synchronized(lock) {if (i % 2 == 1) println("${Thread.currentThread().name}:${i++}")}
}
println("${Thread.currentThread().name} cost time:${System.currentTimeMillis() - start}")
}
fun printEven(start:Long) {
while (i < final) {
synchronized(lock) {if (i % 2 == 0) println("${Thread.currentThread().name}:${i++}")}
}
println("${Thread.currentThread().name} cost time:${System.currentTimeMillis() - start}")
}
3. 运行结果
此处省略一大堆···
Thread-0:99997
Thread-1:99998
Thread-0:99999
Thread-1:100000
Thread-0 cost time:2380
Thread-1 cost time:2380
第二种:使用Object的wait/notify机制
0. 原理
使用kotlin的锁机制,在A线程执行完成后就再唤醒B线程执行,如此反复,避免了线程之间的竞争。
1. 创建运行函数
fun main() {
val start = System.currentTimeMillis()
thread { printOddSync(start) }
thread { printEvenSync(start) }
}
2.两个线程交替打印数字
fun printOddSync(start:Long) {
while (i < final) {
synchronized(lock) {
println("${Thread.currentThread().name}:${i++}")
// 唤醒另外一个线程
lock.notify()
// 本线程进入等待
lock.wait()
}
}
// 退出线程前需要唤醒另外一个线程,避免另外一个线程无限等待
// 因为不知道哪个线程先结束,所以2个线程都需要唤醒另外一个
synchronized(lock) {
lock.notify()
}
println("${Thread.currentThread().name} cost time:${System.currentTimeMillis() - start}")
}
fun printEvenSync(start:Long) {
while (i < final) {
synchronized(lock) {
println("${Thread.currentThread().name}:${i++}")
// 唤醒另外一个线程
lock.notify()
// 本线程进入等待
lock.wait()
}
}
// 退出线程前需要唤醒另外一个线程,避免另外一个线程无限等待
// 因为不知道哪个线程先结束,所以2个线程都需要唤醒另外一个
synchronized(lock) {
lock.notify()
}
println("${Thread.currentThread().name} cost time:${System.currentTimeMillis() - start}")
}
3. 运行结果
此处省略一大堆···
Thread-1:99997
Thread-0:99998
Thread-1:99999
Thread-0:100000
Thread-0 cost time:1017
Thread-1 cost time:1017
综述
使用wait\notify机制可以有效的避免由于线程竞争带来的性能损耗。
网友评论