并发线程之间的协作
Java并发(五):线程之间的协作
前面的笔记中提到了,当使用线程来同时运行多个任务时,可以通过使用锁(互斥)来同步两个任务,从而使得一个任务不会干涉另一个任务的资源。而当多个线程可以一起工作去解决某个问题时,如果某些部分必须在其它部分之前完成,那么就需要对线程进行协调。
关于协调的一种方式join(),在笔记:Java并发(二):基本线程机制之再续前缘中有使用方式的介绍。接下来介绍的是线程之间协调的其他方式。
一、wait()、notify()和notifyAll()
调用wait()使得线程等待某个条件满足,线程在等待时被挂起,当其他线程的运行使得这个条件满足时,其它线程会调用notify()或者notifyAll()来换线挂起的线程。
wait()、notify()和notifyAll()都是属于Object的一部分,而不是属于Thread。并且只能用在同步方法或者同步控制块中,否则在运行时会抛出IllegalMnitorStateException。
使用wait()挂起期间,线程会释放锁。这是因为,如果没有释放锁,那么其它线程就无法进入对象的同步方法或者同步控制块中,也就无法执行notify()或者notifyAll()来唤醒挂起的线程,造成死锁。
Ps:wait()方法可以指定线程的等待时间。因此时间到期之后,线程也会恢复。
wait()和sleep()的区别:
wait()是Object的方法,sleep()是Thread的静态方法。
wait()会释放锁,而sleep()不会。
值得一提的是,join()是通过wait()来实现的,因此使用join()也能够释放锁。
notify()和notifyAll()的区别:
对于多个任务的单个对象处于wait()状态,调用notifyAll()方法比调用notify()方法更安全。notify()方法在众多等待同一个锁的任务中只有一个会被唤醒,因此除非能够保证被唤醒的是恰当的任务(例如所有任务等待相同的条件),否则由于线程调度机制的非确定性,可能会导致死锁。而notifyAll()则是唤醒所有等待同一个锁的所有任务。
而事实上,notifyAll()真正唤醒的是等待该条件的任务,并非所有任务。
二、await()、signal()以及signalAll()
Java SE5的java.util.concurrent类库中提供了Condition类来实现线程之间的协作,可以在Condition上调用await()方法使线程等待,其它线程调用signal()或signalAll()方法唤醒等待的线程。
相比于wait()这种等待方式,await()可以指定等待的条件,因此更加灵活。
参考资料:《Java编程思想》
- 点赞
- 收藏
- 关注作者
评论(0)