摘要:服务器
当线程被建立并启动之后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。在线程的生命周期中,它要通过新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5种状态。尤为是当线程启动之后,它不可能一直"霸占"着CPU独自运行,因此CPU须要在多条线程之间切换,因而线程状态也会屡次在运行、阻塞之间切换并发
1. 新建状态,当程序使用new关键字建立了一个线程以后,该线程就处于新建状态,此时仅由JVM为其分配内存,并初始化其成员变量的值测试
2. 就绪状态,当线程对象调用了start()方法以后,该线程处于就绪状态。Java虚拟机会为其建立方法调用栈和程序计数器,等待调度运行spa
3. 运行状态,若是处于就绪状态的线程得到了CPU,开始执行run()方法的线程执行体,则该线程处于运行状态操作系统
4. 阻塞状态,当处于运行状态的线程失去所占用资源以后,便进入阻塞状态线程
5. 在线程的生命周期当中,线程的各类状态的转换过程设计
当程序使用new关键字建立了一个线程以后,该线程就处于新建状态,此时它和其余的Java对象同样,仅仅由Java虚拟机为其分配内存,并初始化其成员变量的值。此时的线程对象没有表现出任何线程的动态特征,程序也不会执行线程的线程执行体。对象
当线程对象调用了start()方法以后,该线程处于就绪状态。Java虚拟机会为其建立方法调用栈和程序计数器,处于这个状态中的线程并无开始运行,只是表示该线程能够运行了。至于该线程什么时候开始运行,取决于JVM里线程调度器的调度。blog
调用线程对象的start()方法以后,该线程当即进入就绪状态——就绪状态至关于"等待执行",但该线程并未真正进入运行状态。若是但愿调用子线程的start()方法后子线程当即开始执行,程序可使用Thread.sleep(1) 来让当前运行的线程(主线程)睡眠1毫秒,1毫秒就够了,由于在这1毫秒内CPU不会空闲,它会去执行另外一个处于就绪状态的线程,这样就可让子线程当即开始执行。生命周期
若是处于就绪状态的线程得到了CPU,开始执行run()方法的线程执行体,则该线程处于运行状态,若是计算机只有一个CPU。那么在任什么时候刻只有一个线程处于运行状态,固然在一个多处理器的机器上,将会有多个线程并行执行;当线程数大于处理器数时,依然会存在多个线程在同一个CPU上轮换的现象。
当一个线程开始运行后,它不可能一直处于运行状态(除非它的线程执行体足够短,瞬间就执行结束了)。线程在运行过程当中须要被中断,目的是使其余线程得到执行的机会,线程调度的细节取决于底层平台所采用的策略。对于采用抢占式策略的系统而言,系统会给每一个可执行的线程一个小时间段来处理任务;当该时间段用完后,系统就会剥夺该线程所占用的资源,让其余线程得到执行的机会。在选择下一个线程时,系统会考虑线程的优先级。
全部现代的桌面和服务器操做系统都采用抢占式调度策略,但一些小型设备如手机则可能采用协做式调度策略,在这样的系统中,只有当一个线程调用了它的sleep()或yield()方法后才会放弃所占用的资源——也就是必须由该线程主动放弃所占用的资源。
当发生以下状况时,线程将会进入阻塞状态
① 线程调用sleep()方法主动放弃所占用的处理器资源
② 线程调用了一个阻塞式IO方法,在该方法返回以前,该线程被阻塞
③ 线程试图得到一个同步监视器,但该同步监视器正被其余线程所持有。关于同步监视器的知识、后面将存更深刻的介绍
④ 线程在等待某个通知(notify)
⑤ 程序调用了线程的suspend()方法将该线程挂起。但这个方法容易致使死锁,因此应该尽可能避免使用该方法
当前正在执行的线程被阻塞以后,其余线程就能够得到执行的机会。被阻塞的线程会在合适的时候从新进入就绪状态,注意是就绪状态而不是运行状态。也就是说,被阻塞线程的阻塞解除后,必须从新等待线程调度器再次调度它。
针对上面几种状况,当发生以下特定的状况时能够解除上面的阻塞,让该线程从新进入就绪状态:
① 调用sleep()方法的线程通过了指定时间。
② 线程调用的阻塞式IO方法已经返回。
③ 线程成功地得到了试图取得的同步监视器。
④ 线程正在等待某个通知时,其余线程发出了个通知。
⑤ 处于挂起状态的线程被调甩了resdme()恢复方法。
图 2.1 线程状态转换图
从图2.1中能够看出,线程从阻塞状态只能进入就绪状态,没法直接进入运行状态。而就绪和运行状态之间的转换一般不受程序控制,而是由系统线程调度所决定。当处于就绪状态的线程得到处理器资源时,该线程进入运行状态;当处于运行状态的线程失去处理器资源时,该线程进入就绪状态。但有一个方法例外,调用yield()方法可让运行状态的线程转入就绪状态。关于yield()方法后面有更详细的介纽。
线程会以以下3种方式结束,结束后就处于死亡状态:
① run()或call()方法执行完成,线程正常结束。
② 线程抛出一个未捕获的Exception或Error。
③ 直接调用该线程stop()方法来结束该线程——该方法容易致使死锁,一般不推荐使用。
当主线程结束时,其余线程不受任何影响,并不会随之结束。一旦子线程启动起来后,它就拥有和主线程相同的地位,它不会受主线程的影响。为了测试某个线程是否已经死亡,能够调用线程对象的isAlivc()方法,当线程处于就绪、运行、阻塞了种状态时,该方法将返回true;当线程处于新建、死亡状态时,该方法将返回false。
下面程序尝试对处于死亡状态的线程再次调用start()。
main 0 main 1 main 2 main 3 main 4 main 5 main 6 main 7 main 8 main 9 main 10 |
main 11 main 12 main 13 main 14 main 15 main 16 main 17 main 18 main 19 main 20 true |
main 21 ………… Thread-0 0 Thread-0 1 Thread-0 2 Thread-0 3 Thread-0 4 Thread-0 5 Thread-0 6 Thread-0 7 Thread-0 8 |
……………… Thread-0 92 Thread-0 93 Thread-0 94 Thread-0 95 Thread-0 96 Thread-0 97 Thread-0 98 Thread-0 99 main 25 Exception |
main→主线程 Thread-0→线程1 Exception→异常 |
上面程序中的粗体字代码试图在线程已死亡的状况下再次调用start()方法来启动该线程。运行上面程序,将引起IllegaIThreadStateException异常,这代表处于死亡状态的线程没法再次运行了。
若是,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
若是,您但愿更容易地发现个人新博客,不妨点击一下左下角的【关注我】。
若是,您对个人博客所讲述的内容有兴趣,请继续关注个人后续博客,我是【Sunddenly】。本文版权归做者和博客园共有,欢迎转载,但未经做者赞成必须保留此段声明,且在文章页面明显位置给出原文链接,不然保留追究法律责任的权利