Java中线程的状态,是线程在生命周期中不同时间段的状态。举个例子,我们拿小白做作业的例子比作是一条线程要执行的任务。小白掏出作业还没有开始写作业,这就说明线程准备好了。小白开始动笔写了,他在写作业了,他在奋笔疾书的写作业了,这说明线程在运行状态。小白的弟弟小黑把他笔抢去捅蚂蚁洞了,现在小白没法做作业了(他怎么就一个笔?剧情需要....),现在这条线程阻塞状态了也可能是等待状态。小白把小黑揍了一顿,抢来笔继续写作业,现在是线程又是运行状态了。几经波折,小白终于做完了作业了,线程结束。
Java中线程有几种状态
既然谈到线程,怎么离得开Thread这个类。Java中的几个状态也都写在这个类的源码里面了。
在Thread这个类中有一个内部枚举类型。看看源码。
public class Thread implements Runnable {
//省略n多源码...详情看源码
/**
* A thread state. A thread can be in one of the following states:
* 线程状态。一个线程的状态就下面这些了。
*
* 省略n多注释...详情看源码
*/
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
//省略n多源码...详情看源码
}
一共6种状态。但是,如果你看过很多大佬画的图,你会发现,他们画的图中,会还有一种是RUNNING的状态?(不信你去百度)但是这个JAVA只有一个RUNNABLE。怎么回事呢?请往下看。
Runnable和Running状态的区别、
为什么大部分JAVA线程状态图里都有RUNNING状态,但是JAVA源码里没有这个状态呢??
因为JAVA没法用代码把线程变成RUNNING状态,他只能让线程是准备好运行的状态RUNNABLE。
不正经举例:
就像妃子们没法控制自己今晚会不会被翻牌(代表RUNNING状态),她们只能准备好被翻牌,也就是RUNNABLE状态。其实CPU也不是同步运行所有线程的,每次它只能运行一个线程,就像每次皇上只能翻一个妃子的牌一样。
CPU只会不断的切换运行的线程,如果切换的足够快,看上去就像是两个线程在同步运行。
(你可以想象一个反复横跳的人,只要他跳的足够快,你看上去也就是有两个人了,好像是影分身。但其实还是只有一个人,不断的挑来跳去罢了,就像CPU不断的切换运行的线程一样。)
结论
running状态对于线程来说是存在的。但是java控制不了,只能把线程变成runable状态。所以源码中也就没有running了。
实在不懂,学习的时候可以把runable和running看成一个状态就好了。或者就看成7种状态。
注意
虽然java无法将runable状态变成runing状态,但是他可以把running状态变成runable状态。。。。。。。。。通过yield();方法。
JAVA线程状态图
下面是要给简单的图,表示这个线程运行的很顺利,走的也很流畅。没有什么复杂的操作。没有什么很复杂的箭头。
下面来个复杂一点点的图
说明
序号
方法
①
thread.start()
②
代码(方法/代码块)被synchronized修饰,线程等待获取锁。
③
线程获取了锁。
④
.yield();
⑤
.sleep(long);
.wait(long);
.join(long);
LockSupport.parkNanos(long);
LockSupport.parkUntil();
⑥
.notify();
.notifyAll();
LockSupport.unpark(thread);
⑦
.wait();
.join();
LockSupport.park();
⑧
.notify();
.notifyAll();
LockSupport.unpark(thread);
⑨
线程里的代码运行结束
线程抛出一个没有捕获的异常或者error
线程各个状态说明和代码实例
NEW
新建状态新建线程对象。
public static void main(String[] args) {
Thread thread=new Thread(new Runnable() {
public void run() {
System.out.println("我是一个新建的线程");
}
});
//通过.getState();可以获取线程状态
System.out.println(thread.getState());
}
输出:NEW
RUNNABLE
运行.start()将线程变成就绪状态,随时准备着被cpu翻牌。
public static void main(String[] args) {
Thread thread=new Thread(new Runnable() {
public void run() {
System.out.println("我是一个新建的线程");
}
});
//start线程
thread.start();
System.out.println(thread.getState());
}
输出:
RUNNABLE
我是一个新建的线程
BLOCKED
线程在等待其他线程把公用的锁对象释放,所以他就一直blocked。就像小白一直等着他弟弟把笔还给他一样。
自定义一个线程类,运行run()方法中要有同步代码块。然后写一个死循环,让代码一直运行,也就一直不释放锁对象。
public class MyThread extends Thread {
private Object clock;
//锁对象
public MyThread(Object clock){
this.clock=clock;
}
@Override
public void run() {
synchronized (clock){
//让这个线程一直运行,所以他就不会释放clock锁给其他线程用
while (true){}
}
}
}
测试代码
public static void main(String[] args)throws Exception {
Object clock=new Object();
//两个线程使用同一个锁对象
MyThread myThread1=new MyThread(clock);
MyThread myThread2=new MyThread(clock);
//启动两个线程
myThread1.start();
myThread2.start();
//为了不断输出线程的状态,我们在主线程里也写要给死循环。这样就能不断输出线程的状态了。
while (true){
System.out.println("myThread1状态是:"+myThread1.getState());
System.out.println("myThread2状态是:"+myThread2.getState());
//没过3秒输出一次
Thread.sleep(3*1000);
}
}
输出
myThread1状态是:RUNNABLE
myThread2状态是:BLOCKED
myThread1状态是:RUNNABLE
myThread2状态是:BLOCKED
myThread1状态是:RUNNABLE
myThread2状态是:BLOCKED
myThread1状态是:RUNNABLE
myThread2状态是:BLOCKED
.......
WAITING
线程进入等待状态,只有其他线程调用⑧中的方法,才会重新进入RUNNABLE状态。
public static void main(String[] args)throws Exception {
Thread thread=new Thread(new Runnable() {
public void run() {
LockSupport.park();
}
});
thread.start();
//同样的套路,把主线程循环,每3秒输出一下线程的状态
while (true){
System.out.println(thread.getState());
Thread.sleep(3*1000);
}
}
输出
RUNNABLE
WAITING
WAITING
WAITING
....
第一个是因为运行太快了,thread线程还没来得及运行完LockSupport.park();主线程就把他状态输出了。
TIMED_WAITING
这个状态跟上面相似,不过这个状态不一定需要别的线程调用notifyAll()这些方法来重新启动线程,在规定的时间后,此状态的线程会自动变成RUNNABLE状态。
注意是不一定需要
将上面的LockSupport.park();改成LockSupport.parkUntil(10*1000);。意识是10秒后自动从TIMED_WAITING变成RUNNABLE。
while (true){
LockSupport.parkNanos(30*1000);
}
输出
RUNNABLE
TIMED_WAITING
TIMED_WAITING
....
TERMINATED
就是线程运行结束了的状态。
直接上代码
public void run1() throws Exception{
Thread thread=new Thread(new Runnable() {
public void run() {
System.out.println("线程运行结束了");
}
});
thread.start();
//主线程休眠1秒,保证thread运行结束
Thread.sleep(1000);
System.out.println(thread.getState());
}
输出:
线程运行结束了
TERMINATED