如果要实现我们“非阻塞式”的要求,又要怎么办呢?耗时是不得不接受的客观条件,而上面的等待是用于保证顺序性的方法。很明显,我们只能改变等待这个方法。main 线程完成 work1 之后先不急着做 work3,main 线程也不要 “干等” work3,而是先去做点其他的工作,(我们只需要在一个 work流 内的 work1,work2,work3 之间保持顺序,如果其他工作也需要跟这些 work 保持顺序,说明他们也应该在这个工作流内),等 newThread 完成 work2 之后“通知” main 线程,main 线程再在合适的时机继续完成 work3
代码我们可以这样写:
// Thread3.kt
val work = Runnable {
printlnWithThread("do work 1")
switchThread3()
}
val otherWork1 = Runnable {
Thread.sleep(100) // 模拟耗时, 避免main方法中work结束太早,newThread添加work3失败
printlnWithThread("do work a")
}
val otherWork2 = Runnable {
printlnWithThread("do work X")
}
// prevent ConcurrentModificationException
val works = ConcurrentLinkedQueue<Runnable>()
fun main() {
works.addAll(listOf(work, otherWork1, otherWork2))
works.forEach { it.run() }
}
fun switchThread3() = thread {
printlnWithThread("do work 2")
works.add(Runnable { printlnWithThread("do work 3") })
}
运行结果如下:
main: do work 1 Thread-0: do work 2 main: do work a main: do work X main: do work 3 |
在 main方法中,main 线程依次执行完成 work里的 work1, otherWork1, otherWork2,在 work 里启动了一个 newThread 执行 work2,完成 work2 之后 newThread 通过向 main 线程的任务列表添加任务的方式又”切“了一次线程,同时 main 线程正在执行 otherWork1,然后是 otherWork2,最后是 newThread 向 main 线程添加的 work3。从log 可以看出,我们最终完成了我们预期的“切”线程的任务。work 保持了 work1,work2,work3 的顺序工作流,而且也没有通过 main 线程“干等”的方式来保证 subwork 之间的同步性