理性和感性的关系suspend()和resume()⽅法,notify()和wait()⽅法
区别
suspend() 和 resume() ⽅法:两个⽅法配套使⽤,suspend()使得线程进⼊阻塞状态,并且不会⾃动恢复,必须其对应的 resume() 被调⽤,才能使得线程重新进⼊可执⾏状态。典型地,suspend() 和 resume() 被⽤在等待另⼀个线程产⽣的结果的情形:测试发现结果还没有产⽣后,让线程阻塞,另⼀个线程产⽣了结果后,调⽤ resume() 使其恢复。但suspend()⽅法很容易引起死锁问题,已经不推荐使⽤了。
wait() 和 notify() ⽅法:两个⽅法配套使⽤,wait() 使得线程进⼊阻塞状态,它有两种形式,⼀种允许指定以毫秒为单位的⼀段时间作为参数,另⼀种没有参数,前者当对应
广州公积金提取的 notify() 被调⽤或者超出指定时间时线程重新进⼊可执⾏状态,后者则必须对应的 notify() 被调⽤。前台文员工作内容
初看起来它们与 suspend() 和 resume() ⽅法对没有什么分别,但是事实上它们是截然不同的。区别的核⼼在于,前⾯叙述的所有⽅法,阻塞时都不会释放占⽤的锁(如果占⽤了的话),⽽这⼀对⽅法则相反。
银和铝的鉴别方法
上述的核⼼区别导致了⼀系列的细节上的区别。
北京交通大学研究生
⾸先,前⾯叙述的所有⽅法都⾪属于 Thread 类,但是这⼀对却直接⾪属于 Object 类,也就是说,所有对象都拥有这⼀对⽅法。初看起来这⼗分不可思议,但是实际上却是很⾃然的,因为这⼀对⽅法阻塞时要释放占⽤的锁,⽽锁是任何对象都具有的,调⽤任意对象的 wait() ⽅法导致线程阻塞,并且该对象上的锁被释放。⽽调⽤任意对象的notify()⽅法则导致因调⽤该对象的 wait() ⽅法⽽阻塞的线程中随机选择的⼀个解除阻塞(但要等到获得锁后才真正可执⾏)。
十月一号是什么星座
想长高吃什么钙片其次,前⾯叙述的所有⽅法都可在任何位置调⽤,但是这⼀对⽅法却必须在 synchronized ⽅法或块中调⽤,理由也很简单,只有在 synchronized ⽅法或块中当前线程才占有锁,才有锁可以释放。同样的道理,调⽤这⼀对⽅法的对象上的锁必须为当前线程所拥有,这样才有锁可以释放。因此,这⼀对⽅法调⽤必须放置在这样的 synchronized ⽅法或块中,该⽅法或块的上锁对象就是调⽤这⼀对⽅法的对象。若不满⾜这⼀条件,则程序虽然仍能编译,但在运⾏时会出现IllegalMonitorStateException 异常。
锯缘
wait() 和 notify() ⽅法的上述特性决定了它们经常和synchronized ⽅法或块⼀起使⽤,将它们和操作系统的进程间通信机制作⼀个⽐较就会发现它们的相似性:synchronized⽅法或块提供了类似于操作系统原语的功能,它们的执⾏不会受到多线程机制的⼲扰,⽽这⼀对⽅法则相当于 block 和wakeup 原语(这⼀对⽅法均声明为 synchronized)。它们的结合使得我们可以实现操作系统上⼀系列精妙的进程间通信的算法(如信号量算法),并⽤于解决各种复杂的线程间通信问题。
关于 wait() 和 notify() ⽅法最后再说明两点:
第⼀:调⽤ notify() ⽅法导致解除阻塞的线程是从因调⽤该对象的 wait() ⽅法⽽阻塞的线程中随机选取的,我们⽆法预料哪⼀个线程将会被选择,所以编程时要特别⼩⼼,避免因这种不确定性⽽产⽣问题。
第⼆:除了 notify(),还有⼀个⽅法 notifyAll() 也可起到类似作⽤,唯⼀的区别在于,调⽤ notifyAll() ⽅法将把因调⽤该对象的 wait() ⽅法⽽阻塞的所有线程⼀次性全部解除阻塞。当然,只有获得锁的那⼀个线程才能进⼊可执⾏状态。
谈到阻塞,就不能不谈⼀谈死锁,略⼀分析就能发现,suspend() ⽅法和不指定超时期限的 wait() ⽅法的调⽤都可能产⽣死锁。遗憾的是,并不在语⾔级别上⽀持死锁的避免,我们在编程中必须⼩⼼地避免死锁。
以上我们对中实现线程阻塞的各种⽅法作了⼀番分析,我们重点分析了 wait() 和 notify() ⽅法,因为它们的功能最强⼤,使⽤也最灵活,但是这也导致了它们的效率较低,较容易出错。实际使⽤中我们应该灵活使⽤各种⽅法,以便更好地达到我们的⽬的。