1. 线程生命周期
新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5种状态。
1.1. 新建
l new关键字创建了一个线程之后,该线程就处于新建状态
l JVM为线程分配内存,初始化成员变量值
1.2. 就绪
l 当线程对象调用了start()方法之后,该线程处于就绪状态
l JVM为线程创建方法栈和程序计数器,等待线程调度器调度
1.3. 运行
l 就绪状态的线程获得CPU资源,开始运行run()方法,该线程进入运行状态
1.4. 阻塞
当发生如下情况时,线程将会进入阻塞状态
l 线程调用sleep()方法主动放弃所占用的处理器资源
l 线程调用了一个阻塞式IO方法,在该方法返回之前,该线程被阻塞
l 线程试图获得一个同步锁(同步监视器),但该同步锁正被其他线程所持有。
l 线程在等待某个通知(notify)
l 程序调用了线程的suspend()方法将该线程挂起。但这个方法容易导致死锁,所以应该尽量避免使用该方法
Java中实现线程阻塞的5种方法
(1)线程睡眠:Thread.sleep (long millis)方法,使线程转到阻塞状态。millis参数设定睡眠的时间,以毫秒为单位。当睡眠结束后,就转为就绪(Runnable)状态。sleep()平台移植性好。
(2)线程等待:Object类中的wait()方法,导致当前的线程等待,直到其他线程调用此对象的 notify() 唤醒方法。这个两个唤醒方法也是Object类中的方法,行为等价于调用 wait() 一样。wait() 和 notify() 方法:两个方法配套使用,wait() 使得线程进入阻塞状态,它有两种形式,一种允许 指定以毫秒为单位的一段时间作为参数,另一种没有参数,前者当对应的 notify() 被调用或者超出指定时间时线程重新进入可执行状态,后者则必须对应的 notify() 被调用.
(3)线程礼让,Thread.yield() 方法,暂停当前正在执行的线程对象,把执行机会让给相同或者更高优先级的线程。yield() 使得线程放弃当前分得的 CPU 时间,但是不使线程阻塞,即线程仍处于可执行状态,随时可能再次分得 CPU 时间。调用 yield() 的效果等价于调度程序认为该线程已执行了足够的时间从而转到另一个线程.
(4)线程自闭,join()方法,等待其他线程终止。在当前线程中调用另一个线程的join()方法,则当前线程转入阻塞状态,直到另一个进程运行结束,当前线程再由阻塞转为就绪状态。
(5)Callable接口支持返回执行结果,此时需要调用FutureTask.get()方法实现,此方法会阻塞主线程直到获取‘将来’结果;当不调用此方法时,主线程不会阻塞!
1.5. 死亡
线程会以如下3种方式结束,结束后就处于死亡状态:
l run()或call()方法执行完成,线程正常结束。
l 线程抛出一个未捕获的Exception或Error。
l 调用该线程stop()方法来结束该线程,该方法容易导致死锁,不推荐使用。