线程交替打印奇偶数

2019-10-11  本文已影响0人  0一缕星光0

    面试经常性问到要求手写线程交替打印奇偶数,其实就是考察对线程的灵活控制,本次就用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机制可以有效的避免由于线程竞争带来的性能损耗。


源码

线程交替打印奇偶数

上一篇 下一篇

猜你喜欢

热点阅读