今天继续回到Java多线程的基础问题上。今天主要想说一下:线程的状态
在这里需要说一下,由于刚开始写文章不久,总是想到什么就写什么,可能就会出现基础讲讲,跳到进阶,然后又跑到基础,而且内容里面的表达可能也不是很准确,希望大家能够原谅。我会慢慢改进,后面如果写系列文章的话会先做一个整体的规划。尽量不要像现在这么乱了。好了不说了,再说就变成水文了。
线程的状态
开局一张图,内容全靠水。。。

线程状态.png
- new(新建状态):当我们新new一个线程后,这个线程就是新建状态
Thread t = new Thread() - ready(就绪状态):new了一个线程,调用线程的start()方法后,这个线程将会进入就绪状态,这个时候他只是具备了可执行的条件,但是还是没有执行
- running(执行状态):就绪状态中的线程其实是被扔到了CPU的等待队列排对等待翻牌子去了。等到CPU翻到了谁的牌子,谁就进入了执行状态。学过了yield之后我们都知道,调用它会让执行状态的线程直接让出当前CPU跑到就绪状态继续排队
- blocking(阻塞状态):当我们在线程中使用了synchronized关键字时,当代码运行到这里是需要获取锁之后才能继续执行,这种状态叫做阻塞状态,由于阻塞时候CPU就会放弃你,所以当我获取到锁之后我才会进入到就绪状态再去排队等待CPU翻牌子
- waitting(等待状态):当运行中的线程调用了wait(),join(),park()方法后,线程会等待其他线程执行完成或者使用其他的方法来唤醒才能继续进入执行状态
- timeWaitting(有时间等待状态):当运行中的线程调用了sleep(tiem)和调用上诉的方法带上时间,线程会在那里等待直到时间结束就会自动进入执行状态
- over(结束状态):当一个线程正常执行完成,或者上诉所有状态运行过程中抛出异常或调用interrupt方法都会让线程进入到结束状态。当线程进入结束状态后就无法再进行其他的状态转换,只有重新new才可以重新运行
我们可以通过简单的小程序来看到部分的线程状态:
public class ThreadStateTest {
static class MyThread extends Thread {
@Override
public void run() {
try {
Thread.sleep(3000);
System.out.println("sleep 之后的状态:" + Thread.currentThread().getState());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
MyThread myThread = new MyThread();
System.out.println("new 之后的状态:" + myThread.getState());
myThread.start();
System.out.println("start 之后的状态:" + myThread.getState());
myThread.join();//等待线程去死
System.out.println("join 之后的状态:" + myThread.getState());
}
}
注意
有一点需要注意,调用Lock的一些方法并不会让线程进入blocked状态,而是会让线程进入waitting状态。
public class LockTests {
Lock lock = new ReentrantLock();
public static void main(String[] args) {
LockTests lockTest = new LockTests();
// 可重入锁 + 基本使用 案例开始
for (int i = 0;i<3;i++) {
new Thread(()->{lockTest.tryLockTest();}, "线程 " + i).start();
}
}
public synchronized void tryLockTest(){
try {
try {
Thread.sleep(10000);
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
在他执行的时候,我们使用jstack -l pid 命令就可以看到如下图的样子:
[图片上传失败...(image-645e24-1698156369246)]
可以看到,没有获取到锁的线程的状态是blocked 的没有问题,而且也看出了synchronized关键字实现锁的方式是使用monitor
再看下面一个小程序:
public class LockTests {
Lock lock = new ReentrantLock();
public static void main(String[] args) {
LockTests lockTest = new LockTests();
// 可重入锁 + 基本使用 案例开始
for (int i = 0;i<3;i++) {
new Thread(()->{lockTest.tryLockTest();}, "线程 " + i).start();
}
}
public void tryLockTest(){
try {
if (lock.tryLock(50, TimeUnit.SECONDS)) {
try {
Thread.sleep(10000);
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
由于我们使用的是tryLock(time) 所以没有获取到锁的状态是timed_waitting 可以看到他锁定的方式是使用park,这个我准备下一篇会说一下。他是locksupport工具类里面的方法。
总结
本篇文章总共讲了线程的7中状态:new、runnable、running、blocking(blocked)、waitting、time_waitting、over(dead)
顺便提了一个小的排查线程问题的工具:jstack