在平常开发过程当中,若是咱们须要执行一些比较耗时的程序的话,通常来讲都是开启一个新线程,把耗时的代码放在线程里,而后开启线程执行。但线程是会耗费系统资源的,若是有多个线程同时运行,互相之间抢占系统资源,那无疑会对系统形成极大的压力。因此,怎么操做线程,保证不影响整个应用功能是很重要的,而这就须要咱们了解线程的生命周期了。架构
线程的生命周期有6种状态,分别是 NEW(新建)、RUNNABLE(可运行)、BLOCKED(被阻塞)、 WAITING(等待)、TIMED_WAITING(计时等待)、TERMINATED(被终止) ,在 Thread 源码的 State 枚举中都有定义:并发
public static enum State { NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED; private State() { } }
一、 NEW 状态表示刚刚建立的线程,此时的线程还没运行,也就是还没执行start() 方法,建立线程的方式也比较简单,能够参考《Java并发知识:Java建立线程的三种方式》。ide
二、当线程执行时,处于 RUNNABLE 状态,表示线程所需的资源已经准备好了。工具
三、若是线程在执行的过程当中遇到被阻塞的状况,例如线程中的程序中有synchronized 同步代码块,线程就会暂停执行,进入阻塞状态,直至获取请求的锁,这时线程就处于 BLOCKED 状态。学习
实例代码以下:this
public class ThreadDemo { public static Object testObject = new Object(); public static class MyThread extends Thread { public MyThread(String name) { super.setName(name); } @Override public void run() { //每次跑run方法都须要获取testObject对象 synchronized (testObject) { System.out.println("thread name:" + this.getName()); //..............耗时操做.............. } } } public static void main(String[] args) { for (int i = 1; i <= 100; i++) { new MyThread("线程"+i).start(); } } }
在上面的代码中,线程的run方法在执行耗时的程序以前都须要先获取testobject对象的锁,由于对象锁是公共对象,因此,多个线程同时运行时,同一时刻只能有一个线程获取锁,假设某个时刻是 A线程 获取了锁,其余线程就会处于等待锁释放的阻塞状态,直到获取锁才能继续执行程序,这就是线程的 BLOCKED 状态。spa
四、 WAITING 表示等待的状态,处于 WAITING 状态的线程会进入一个 无时间限制 的等待,一旦等到了指望的事件,线程就会再次执行,进入 RUNNABLE 状态。最典型的场景就是 等待(wait) 和 通知(notify) 。线程
等待状态对应的方法是wait(),而通知是notify(),这两个方法并不属于Thread类,而是属于Object类,因此全部对象均可以使用这两个方法。当一个对象实例 obj 调用 wait() 方法后,当前线程就会在这个对象上等待,直到其余线程调用 obj.notify() 为止。这时的对象实例 obj 就至关于多个线程之间的通讯工具。实例代码以下:3d
public class ThreadDemo { public static Object testObject = new Object(); public static class MyThread1 extends Thread { @Override public void run() { synchronized (testObject) { System.out.println("MyThread1 wait :" + System.currentTimeMillis()); try { //调用wait方法进入等待状态 testObject.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static class MyThread2 extends Thread { @Override public void run() { synchronized (testObject) { System.out.println("MyThread2 start notify :" + System.currentTimeMillis()); //..............耗时操做.............. //发出通知,唤醒等待的线程 testObject.notify(); } } } public static void main(String[] args) { MyThread1 t1 = new MyThread1(); MyThread2 t2 = new MyThread2(); t1.start(); t2.start(); } }
五、 TIMED_WAITING 和 WAITING 同样,都表示等待状态,但TIMED_WAITING 会进行一个 有时限的等待 。操做线程状态有几个方法是带有超时参数的,调用方法的线程进入计时等待状态。这一状态将一直保持到超时期满或者接收到适当的通知,最多见的应用就是调用 Thread.sleep() 方法。视频
实例代码以下:
public static class MyThread extends Thread { @Override public void run() { System.out.println("MyThread start :" + System.currentTimeMillis()); try { //休眠两秒钟 Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("MyThread end :" + System.currentTimeMillis()); } } public static void main(String[] args) { MyThread t = new MyThread1(); t.start(); }
启动线程后,程序运行到 Thread.sleep() 方法会处于休眠状态,时间根据参数来决定,单位是毫秒,因此执行main方法后,后一条输出内容会隔两秒钟出现。在此我向你们推荐一个架构学习交流裙。交流学习裙号:681179158,里面会分享一些资深架构师录制的视频录像
MyThread start :1544704974271 MyThread end :1544704976272
六、当线程执行完毕后,进入 TERMINATED 状态,表示结束,通常线程被终止有两种缘由:
run方法正常运行后就天然消亡。
由于一个没有捕获的异常终止了run方法而致使意外死亡。
好了,线程的生命周期就总结完了,用一张图表示大概是这样: