企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持知识库和私有化部署方案 广告
# 线程的生命周期 [TOC] ## 线程的状态 线程存在五个状态: * 创建状态(new) * 就绪状态(runnable) * 运行状态(running) * 阻塞状态(blocked) * 终止状态(dead) ![](https://img.kancloud.cn/b9/f8/b9f8d01446680df20aa4eef96138c163_796x525.png) >[warning]需要注意的是,stop()方法现已不建议使用了 ## 状态详解 * **创建状态** 在程序中使用构造方法创建一个线程对象后,新的线程对象便处于新建状态。此时,它已经有了相应的内存空间和其他资源,但还是处于不可运行状态。 比如可以`Thread myThread = new Thread();` * **就绪状态** 新建线程对象后,调用该线程的`start()`方法就可以启动线程,当线程启动的时候,线程就进入就绪状态。此时线程进入线程队列排队,等待CPU调度服务。 * **运行状态** 当就绪状态的线程被调用并获得处理器资源时,线程就进入了运行状态。此时将自动调用该线程对象的`run()`方法。 * **阻塞状态** 一个正在运行的线程在某些特殊情况下,将让出CPU并暂时停止自己的运行,进入阻塞状态。阻塞时,线程不能进入排队队列,只有当引起阻塞的原因被消除后,线程才会转入就状态 * **终止状态** 当线程体中的`run()`方法运行结束后,线程即处于终止状态,处于终止状态的线程不具有继续运行的能力 ## 线程休眠-sleep()方法的使用 休眠会使线程进入休眠状态 `sleep()`方法是`Thread`类的静态方法,该方法无返回值。 ![](https://img.kancloud.cn/ed/94/ed949f2fa4ecf726137b9d4ed5f24ca9_888x131.png) **作用**:在指定的毫秒数内让正在执行线程休眠(暂停执行) **参数**:参数为休眠的时间,单位是毫秒 ~~~java public class MyRunnable implements Runnable{ @Override public void run() { int i = 1; while(i <= 30) { //打印该线程的当前线程名称 System.out.println(Thread.currentThread().getName()+"say:Hello,World" + i); //休眠1000毫秒后,线程并不是立即进入可运行状态,而是要等待CPU的调度,所以如果使用sleep写一个时钟类的应用可能会有一些误差 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } i++; } } } public class MyRunnableUse { public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread thread = new Thread(myRunnable); thread.start(); Thread thread1 = new Thread(myRunnable); thread1.start(); } } ~~~ **使用场景**: 1. 比如我们可以使用`sleep()`方法计时30秒钟,然后一秒一秒的输出倒计时 2. 在交通类的应用中可以使用`sleep()`方法定期刷新数据,获取最新的交通信息 >[info]使用sleep()方法在休眠相应时间后,转为可运行状态,在获取cpu使用权后进入运行状态;这个方法可能会发生InterruptedException异常,需要强制性的使用try-catch捕获。 ## 线程强制执行-join()方法 在多线程并发执行中每一个线程对象都会交替还行,如果此时某个线程对象中的内容非常重要,需要优先执行完成,则可以设置为强制执行,待其执行完毕后其他线程再继续执行。 ![](https://img.kancloud.cn/03/05/0305b27d20df97f21bd581d0d954f36c_871x130.png) `public final void join()`方法优先执行,抢占资源,该线程执行完后其他线程才能执行,该方法不允许重写。 `public final void join(long millis)`可带参数,等待该进程的最长时间(即该线程占用资源的时间),时间完成后该线程不再拥有优先权,正常执行 ~~~ public class MyThread extends Thread { @Override public void run() { System.out.println(getName() + "线程正在执行"); } } public class ThreadTest { public static void main(String[] args) { MyThread mtf = new MyThread(); mtf.start(); try { mtf.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("主线程运行结束"); } } ~~~ ~~~Java public class MyThread extends Thread { @Override public void run() { for(int i = 0; i < 10; i++) { System.out.println(getName() + "线程正在执行" + i + "次"); } } } public class ThreadTest { public static void main(String[] args) { MyThread mtf = new MyThread(); mtf.start(); try { mtf.join(); } catch (InterruptedException e) { e.printStackTrace(); } for(int i = 0; i < 20; i++) { System.out.println("主线程正在运行第" + i + "次"); } System.out.println("主线程运行结束"); } } ~~~ >[info]使用join()方法也可能会发生InterruptedException异常,需要强制性的使用try-catch捕获。 ## 线程礼让-yield()方法 线程礼让是指当满足某些条件的时候可以将当前的CPU调度让给其他线程执行。如果某些不是很重要的线程抢占到资源但又不急于执行时,就可以将当前的CPU资源礼让出去,交由其他线程先执行。 yield方法定义如下: ![](https://img.kancloud.cn/48/83/4883b9d0ddcf9cbfde43c5076ff78c3b_887x49.png) `public static void yield()` **作用**:表示当前线程对象提示调度器自己愿意让出CPU资源,**但是调度器可以自由忽略。** ~~~Java public class MyThread extends Thread { @Override public void run() { for(int i = 0; i < 10; i++) { if(i == 3) { yield(); } System.out.println(getName() + "线程正在执行" + i + "次"); } } } public class ThreadTest { public static void main(String[] args) { MyThread mtf = new MyThread(); mtf.start(); for(int i = 0; i < 20; i++) { System.out.println("主线程正在运行第" + i + "次"); } System.out.println("主线程运行结束"); } } ~~~ **sleep()和yield()的区别** * 都能是调用的线程放弃CPU,把运行机会给其他线程 * sleep()会给其他线程的运行机会,且不考虑优先级,但是yield()只会给同优先级或更高优先级的线程运行的机会(不一定能运行) * 调用sleep()后,线程进入阻塞状态,而调用yield()后进入就绪状态(随时等待JVM的再次调用) ## 线程优先级 所有创造的线程都是子线程,所有的子线程在启动时都会保持同样的优先权限。但是如果某些重要的线程希望可以优先抢占到CPU资源并且先执行,就可以通过修改线程的优先级实现。 哪个线程的优先级越高,哪个线程就有可能会先执行。 **线程优先级**: * Java为线程类提供了10个优先级 * 优先级可以用整数1-10表示,超出范围会抛出异常 * 主线程默认优先级为5 * 可以使用优先级常量表示优先级 | 方法或常量 | 类型 | 描述 | | :--- | :---: | :--- | | public static final in MAX_PRIORITY | 常量 | 最高优先级,数值为10 | | public static final in NORM_PRIORITY | 常量 | 中等优先级,数值为5 | | public static final in MIN_PRIORITY | 常量 | 最低优先级,数值为1 | | public final void setPriority(int newPriority) | 普通 | 设置线程优先级 | | public final int getPriority() | 普通 | 取得线程优先级 | ~~~java public class MyThread extends Thread { private String name; public MyThread(String name) { this.name = name; } @Override public void run() { for(int i = 0; i < 10; i++) { System.out.println("线程:" + name + "正在执行第" + i + "次"); } } } public class ThreadTest { public static void main(String[] args) { //获得主线程的优先级 //int mainPriority = Thread.currentThread().getPriority(); //System.out.println("主线程优先级为:" + mainPriority); MyThread mtf = new MyThread("子线程1"); MyThread mts = new MyThread("子线程2"); //mtf.setPriority(10); //使用常量设置线程优先级 mtf.setPriority(Thread.MAX_PRIORITY); mts.setPriority(Thread.MIN_PRIORITY); mtf.start(); mts.start(); //System.out.println("子线程1的优先级为:" + mtf.getPriority()); } } ~~~ >[warning]优先级的设置与操作系统的环境和CPU的工作方式都是有很大的关系的。