从操作系统的角度讲,os会维护一个ready queue(就绪的线程对列)。并在某一时刻CPU只为ready queue中位于队列头部的线程服务。但是当前正在被服务的线程可能觉得cpu的服务质量不够好,于是提前退出,这就是yield。或者当前被服务的线程需要睡一会,醒来后继续被服务,这就是sleep。线程退出最好自己实现,在运行状态中一直校验一个状态,如果这个状态为真,就一直运行,如果外界改变了这个状态变量,那么线程就停止运行。sleep使当前线程进入停滞状态,所以执行sleep的线程在指定的时间内肯定不会执行;yield只是使当前线程重绘可执行状态,所以执行yield的线程有可能在进入可执行状态后马上又被执行。sleep可使优先级低的线程得到执行的机会,当然也可以让同优先级和高优先级的线程有执行的机会,yield只能使同优先级的线程有执行的机会,当调用wait后,线程会释放掉他所战友的“锁标志”,从而使线程所在对象中它synchronized数据可被其他线程使用。wait和notify因为会对对象的“锁标志”进行操作,所以它们必须在synchronized函数或synchronized block中进行调用。如果在non-synchronized中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException异常。
一个线程的生命周期:
- 新建状态
使用new关键字和Thread类及其子类建立一个线程对象后,该线程对象就处于新建状态。他保持这个状态直至start这个线程。
- 就绪状态
当线程对象调用了start方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。
- 运行状态
如果就绪状态的线程获取了CPU资源就可以调用run方法,此线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态,就绪状态和死亡状态
- 阻塞状态
如果一个线程执行了Sleep、suspend等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态了。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。
- 死亡状态
一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。
- sleep()
在指定的毫秒数内让当前正在执行的线程休眠,此操作受到系统计时器和调度程序精度和准确性的影响。由于sleep方法是Thread类的方法,因此它不能够改变对象的机锁。所以当在一个synchronized方法中调用sleep()时,线程虽然休眠了,单是对象的机锁没有被释放,其他线程仍然无法访问这个对象。sleep()方法不需要在同步的代码块中执行,但是sleep可以通过interrupt方法打断线程的暂停状态,从而使线程立刻抛出InterruptedException
- wait()、notify()和notifyAll()
wait()方法则会在线程休眠的同事释放掉机锁,其他线程可以访问该对象。wait必须在同步代码块中执行,当一个线程执行到wait方法时,它就进入到一个和该对象相关的等待池中,同时时区了对象的机锁,可允许其他线程执行一些同步操作。但是wait可以通过interrupt方法大胆线程的暂停状态,从而立刻抛出InterruptedException。
wait可以让同步方法或者同步块暂时释放掉对象锁,而将它暂时让给其他需要对象锁的线程或者程序块用,这意味着可在执行wait期间调用小城对象中的其他同步方法。wait所在线程如何收回对象锁呢?
第一种方法,限定借出去的时间,在wait中设置参数,到时自动收回。
第二种方法,使用notify或notifyAll,只有在一个notify或者notifyAll发生变化的时候,线程才会被唤醒。
notify唤醒在此对象监听器上等待的单个线程。当它被一个notify方法唤醒时,等待池中的线程就被放到了锁池中,该线程将等待从锁池中获得机锁,然后回到wait前的中断现场。
notifyAll唤醒在此对象监听器上等待的所有线程。
- suspend()和resume()
suspend和resume必须承兑出现,否则非常容易造成死锁。因为suspend方法不会释放锁,如果suspend的目标线程对一个很重要的系统资源持有锁,难么没任何线程可以使用这个资源直至要Suspend的目标线程被resume,如果一个线程的resume目标线程之前尝试持有这个重要的系统资源锁再去resume目标线程,这两条线程就互相死锁了,也就冻结线程。
- join()
join方法使当前线程停下来等待,直到另一个调用join方法的线程终止。线程在被激活后不一定马上就运行,而是进入到可运行线程队列中。但是join可以通过interrupt方法打断线程的暂停状态。
- yield()
Yield方法是停止当前线程,让同等优先权的线程运行,如果没有同等优先权的线程,那么yield方法将不会起作用。
- interupt()
interrupt中断线程。InterruptedException是线程自己冲内部抛出的,并不是interrupt方法抛出的。对某一线程调用interrupt时,如果该线程正在执行普通的代码,那么该线程根本就不会抛出InterruptedException。但是一旦该线程进入到wailt、join、sleep后,就立刻抛出