# 线程的生命周期
[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的工作方式都是有很大的关系的。