Java线程中sleep()、wait()和notify()和notifyAll()、suspend和resume()、yield()、join()、interrupt()的用法和区别

从操做系统的角度讲,os会维护一个ready queue(就绪的线程队列)。而且在某一时刻cpu只为ready queue中位于队列头部的线程服务。 
可是当前正在被服务的线程可能以为cpu的服务质量不够好,因而提早退出,这就是yield。 
或者当前正在被服务的线程须要睡一会,醒来后继续被服务,这就是sleep。 
sleep方法不推荐使用,可用wait。 
线程退出最好本身实现,在运行状态中一直检验一个状态,若是这个状态为真,就一直运行,若是外界更改了这个状态变量,那么线程就中止运行。 
sleep()使当前线程进入停滞状态,因此执行sleep()的线程在指定的时间内确定不会执行;yield()只是使当前线程从新回到可执行状态,因此执行yield()的线程有可能在进入到可执行状态后立刻又被执行。 
sleep()可以使优先级低的线程获得执行的机会,固然也可让同优先级和高优先级的线程有执行的机会;yield()只能使同优先级的线程有执行的机会。 
当调用wait()后,线程会释放掉它所占有的“锁标志”,从而使线程所在对象中的其它synchronized数据可被别的线程使用。 
waite()和notify()由于会对对象的“锁标志”进行操做,因此它们必须在 synchronized函数或synchronized block中进行调用。若是在non-synchronized函数或non- synchronized block中进行调用,虽然能编译经过,但在运行时会发生IllegalMonitorStateException的异常。 

java

一个线程的生命周

线程通过其生命周期的各个阶段。下图显示了一个线程完整的生命周期。函数

java_thread

  • 新建状态:

    使用 new 关键字和 Thread 类或其子类创建一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。操作系统

  • 就绪状态:

    当线程对象调用了start()方法以后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。线程

  • 运行状态:

    若是就绪状态的线程获取 CPU 资源,就能够执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它能够变为阻塞状态、就绪状态和死亡状态。code

  • 阻塞状态:

    若是一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源以后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或得到设备资源后能够从新进入就绪状态。对象

  • 死亡状态:

    一个运行状态的线程完成任务或者其余终止条件发生时,该线程就切换到终止状态。blog



用法 
sleep() 
在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操做受到系统计时器和调度程序精度和准确性的影响。 

因为sleep()方法是Thread类的方法,所以它不能改变对象的机锁。因此当在一个Synchronized方法中调用sleep()时,线程虽然休眠了,可是对象的机锁没有被释放,其余线程仍然没法访问这个对象。sleep()方法不须要在同步的代码块中执行。可是sleep()能够经过interrupt()方法打断线程的暂停状态,从而使线程马上抛出InterruptedException。 

wait()和notify()和notifyAll() 
wait()方法则会在线程休眠的同时释放掉机锁,其余线程能够访问该对象。wait()必须在同步的代码块中执行。当一个线程执行到wait()方法时,它就进入到一个和该对象相关的等待池中,同时失去了对象的机锁,能够容许其它的线程执行一些同步操做。可是wait()能够经过interrupt()方法打断线程的暂停状态,从而使线程马上抛出InterruptedException。 

wait可让同步方法或者同步块暂时放弃对象锁,而将它暂时让给其它须要对象锁的人(这里应该是程序块,或线程)用,这意味着可在执行wait()期间调用线程对象中的其余同步方法!在其它状况下(sleep啊,suspend啊),这是不可能的.可是注意我前面说的,只是暂时放弃对象锁,暂时给其它线程使用,我wait所在的线程仍是要把这个对象锁收回来的呀.wait什么?就是wait别人用完了还给我啊! 

好,那怎么把对象锁收回来呢? 

第一种方法,限定借出去的时间.在wait()中设置参数,好比wait(1000),以毫秒为单位,就代表我只借出去1秒中,一秒钟以后,我自动收回. 

第二种方法,让借出去的人通知我,他用完了,要还给我了.这时,我立刻就收回来.哎,假如我设了1小时以后收回,别人只用了半小时就完了,那怎么办呢?靠!固然用完了就收回了,还管我设的是多长时间啊. 

那么别人怎么通知我呢?相信你们均可以想到了,notify(),这就是最后一句话"并且只有在一个notify()或notifyAll()发生变化的时候,线程才会被唤醒"的意思了. 

notify()唤醒在此对象监视器上等待的单个线程。当它被一个notify()方法唤醒时,等待池中的线程就被放到了锁池中。该线程将等待从锁池中得到机锁,而后回到wait()前的中断现场。 

notifyAll()唤醒在此对象监视器上等待的全部线程。 


suspend和resume() 
join() 
join()方法使当前线程停下来等待,直至另外一个调用join方法的线程终止。值得注意的是,线程的在被激活后不必定立刻就运行,而是进入到可运行线程的队列中。可是join()能够经过interrupt()方法打断线程的暂停状态,从而使线程马上抛出InterruptedException。 

yield() 
Yield()方法是中止当前线程,让同等优先权的线程运行。若是没有同等优先权的线程,那么Yield()方法将不会起做用。 

interrupt() 
interrupt()中断线程。须要注意的是,InterruptedException是线程本身从内部抛出的,并非interrupt()方法抛出的。对某一线程调用interrupt()时,若是该线程正在执行普通的代码,那么该线程根本就不会抛出InterruptedException。可是,一旦该线程进入到wait()/sleep()/join()后,就会马上抛出InterruptedException。 


各个方法之间的区别生命周期

 

线程方法名称 是否释放同步锁 是否须要在同步的代码块中调用 方法是否已废弃 是否能够被中断
sleep()
wait()
suspend      
resume()      
join()    

 

via:http://zheng12tian.iteye.com/blog/1233638队列

相关文章
相关标签/搜索