1.引言
在本篇博客中主要记录一下线程的状态,线程都存在哪一些状态?如何改变线程的状态。关于线程状态的信息都存储在State
枚举类中。首先我们看一下线程的状态图:
现成的状态大致分为六种:
New
:代表创建了线程对象,但是未执行start
方法。Runable
:代表正在Java虚拟机中正在执行的线程。blocked
:代表线程受阻塞Waiting
:代表无限期的等待,知道其他线程给改线程发表唤醒命令Timed Waiting
:代表线程等待一定的时间Terminated
:代表线程已经退出
2. 验证线程所处的状态
现在我们就来使用 Demo来验证线程在一定情况下所处的状态
2.1 验证New状态
2.1.1 代码示例
- 首先创建一个线程
public class MyThread extends Thread {
public void run() {
}
}
- main方法
public class App {
public static void main(String[] args) throws Exception {
MyThread td=new MyThread();
System.out.println(td.getState());
}
}
- 运行结果
2.1.2代码解释
- 注意:当线程对象创建之后,但是没有执行
start
方法,此时线程的状态为:NEW
2.2 验证Runable状态
2.2.1 代码
- 创建线程
public class MyThread extends Thread {
public void run() {
System.out.println(this.getState());
}
}
- main方法
public class App {
public static void main(String[] args) throws Exception {
MyThread td=new MyThread();
td.start();
}
}
- 运行结果
2.2.2代码解释
- 当代码执行
start
方法之后,线程的状态变为Runable
,注意:此时的线程并未执行完(也就是说线程在执行run
方法),如果执行完,那么线程的状态就变成了terminated
2.3 验证terminated
状态
2.3.1 代码示例
- 线程代码
public class MyThread extends Thread {
public void run() {
}
}
- main函数
public class App {
public static void main(String[] args) throws Exception {
MyThread td=new MyThread();
td.start();
//保证td线程已经执行结束了
Thread.sleep(1000);
System.out.println(td.getState());
}
}
- 运行结果
2.3.2 代码解释
- 当线程运行结束后:线程的状态修改为
terminated
2.4 验证状态Timed_waiting
2.4.1 代码示例
- 自定义线程
public class MyThread extends Thread {
public void run() {
try {
//让子线程睡2秒中。这里也可以是wait(timeout)方法,也可以是join(timeout)方法
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
- main方法
public class App {
public static void main(String[] args) throws Exception {
MyThread td=new MyThread();
td.start();
//保证子线程在睡眠状态
Thread.sleep(1000);
System.out.println(td.getState());
}
}
- 运行结果
2.4.2 代码解释
- 注意:我们不仅仅可以使用sleep方法让线程进入
timed_waiting
状态,也可以使用wait方法和join方法。 - 再次注意:如果想要使用wait或者join方法进入
timed_waiting
,wait
方法必须带参数,比如wait(2000)
,如果使用wait()
方法(不带时间参数),那么将进入waiting
状态
2.5 验证Blocked
状态
2.5.1 代码示例
- 创建service方法
public class service {
public static synchronized void printString() throws Exception {
System.out.println("线程等待5秒钟");
Thread.sleep(5000);
}
}
- 创建线程类
public class MyThread extends Thread {
private Service service;
public MyThread(Service service){
this.service=service;
}
public void run() {
try {
service.printString();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
- main方法
public class App {
public static void main(String[] args) throws Exception {
Service service=new Service();
MyThread td1=new MyThread(service);
MyThread td2=new MyThread(service);
td1.start();
td2.start();
Thread.sleep(1000);
System.out.println(td2.getState());
}
}
- 运行结果
2.5.2 代码解释
- td2线程正在等待获取对象锁,此时线程状态是
Blocked
2.6验证Waiting
状态
2.6.1 代码示例
- 线程代码
public class MyThread extends Thread {
private Object lock;
public MyThread(Object lock){
this.lock=lock;
}
public void run() {
synchronized (lock) {
try {
//注意这里
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
- main方法
public class App {
public static void main(String[] args) throws Exception {
Object lock=new Object();
MyThread td=new MyThread(lock);
td.start();
Thread.sleep(1000);
System.out.println(td.getState());
}
}
- 运行结果
2.6.2代码解释
- 注意状态
Waiting
和状态timed_waiting
的区别 - 执行
wait
方法使线程进入的是Waiting
状态
3.从线程状态解释生产者/消费者模式
通过上面的实例我们已经大致的了解了线程的状态都有哪几种,在什么情况下县线程会进入什么状态,接下来我们使用线程的状态来解释一下:生产者消费者模式(多生产多消费)
3.1 解释生产者/消费者模式
首先我们从消费者说起,首先我们的产品的个数为0,消费者执行wait
方法,然后消费者线程状态修改为waiting
,这里我们可以看出waiting
状态是没有权限争夺对象锁的,也就是一直处于等待状态,然后消费者唤醒生产者线程,生产者生产一个产品,然后唤醒消费者线程,注意:这里唤醒消费者线程假设我们使用的是notifyAll()
方法,那么所有的消费者线程状态将变为Runable
状态的准备阶段(假设我们将Runable状态分为准备阶段和运行阶段),如果某一个线程获取到了对象锁,那么该线程将会进入Runable的运行阶段,其他线程将会进入Blocked
状态(也就是等待获得对象锁,注意:Blocked
状态是有权限获得对象锁的)。以此反复,从而形成了生产者消费者模式。