线程的阻塞

来源:互联网 发布:centos安装gfirefly 编辑:程序博客网 时间:2024/06/01 07:38

 
线程的阻塞  
Java引入了阻塞机制的支持
阻塞指的是暂停一个线程的执行等待某个条件发生,Java提供大量方法支持阻塞:
1. sleep()
    允许指定以毫秒为单位的一段时间作为参数,它使得线程在指定的时间内进入阻塞状态,不能得到CPU 时间,指定的时间一过,线程重新进入可执行状态。
    sleep() 被用在等待某个资源就绪的情形:测试发现条件不满足后,让线程阻塞一段时间后重新测试,直到条件满足为止。

2. suspend()和resume()
   
两个方法配套使用,suspend()使得线程进入阻塞状态,并且不会自动恢复,必须其对应的resume() 被调用,才能使得线程重新进入可执行状态。
   
suspend() 和 resume() 被用在等待另一个线程产生的结果的情形:测试发现结果还没有产生后,让线程阻塞,另一个线程产生了结果后,调用resume()使其恢复。

3. yield()
   
yield() 使得线程放弃当前分得的 CPU 时间,但是不使线程阻塞,即线程仍处于可执行状态,随时可能再次分得 CPU 时间。调用 yield() 的效果等价于调度程序认为该线程已执行了足够的时间从而转到另一个线程。

4. wait() 和notify()
   
两个方法配套使用,wait() 使得线程进入阻塞状态,它有两种形式,一种允许指定以毫秒为单位的一段时间作为参数,另一种没有参数,前者当对应的 notify() 被调用或者超出指定时间时线程重新进入可执行状态,后者则必须对应的 notify() 被调用。



区别

【注】以上叙述的所有方法阻塞时都不会释放占用的锁(如果占用了的话),而wait() 和notify()方法则相反。

       所有对象都拥有wait() 和notify()方法。因为这一对方法阻塞时要释放占用的锁,而锁是任何对象都具有的,调用任意对象的 wait() 方法导致线程阻塞,并且该对象上的锁被释放。而调用任意对象的notify()方法则导致因调用该对象的 wait() 方法而阻塞的线程中随机选择的一个解除阻塞(但要等到获得锁后才真正可执行)。

       以上叙述的所有方法都可在任何位置调用,但是wait() 和notify()方法却必须在 synchronized 方法或块中调用,理由也很简单,只有在synchronized 方法或块中当前线程才占有锁,才有锁可以释放。

        调用wait() 和notify()方法的对象上的锁必须为当前线程所拥有,这样才有锁可以释放。因此,wait() 和notify()方法调用必须放置在这样的 synchronized 方法或块中,该方法或块上锁的对象就是调用wait() 和notify()方法的对象。若不满足这一条件,则程序虽然仍能编译,但在运行时会出现 illegalMonitorStateException 异常。


关于 wait() 和 notify() 方法最后再说明两点:

  第一:调用 notify() 方法导致解除阻塞的线程是从因调用该对象的 wait() 方法而阻塞的线程中随机选取的,无法预料哪一个线程将会被选择,所以编程时要特别小心,避免因这种不确定性而产生问题。

  第二:除了 notify(),还有一个方法 notifyAll() 也可起到类似作用,唯一的区别在于,调用 notifyAll() 方法将把因调用该对象的wait()方法而阻塞的所有线程一次性全部解除阻塞。当然,只有获得锁的那一个线程才能进入可执行状态。



【注】
suspend() 方法和不指定超时期限的 wait() 方法的调用都可能产生死锁。遗憾的是,Java 并不在语言级别上支持死锁的避免,在编程中必须小心地避免死锁。



还有一个方法比较有用,Thread的join()方法可用于让当前线程阻塞,以等待特定线程的消亡。
0 0