学并发编程的时候,我们不仅仅要知道如何创建线程、停止线程,还要知道线程的各种状态,还有线程之间切换的顺序问题,以便我们在寻找问题的时候,更容易解决问题

当线程调用notify或者notifyAll的时候,线程会首先去抢占synchronized的monitor锁,抢到了就进去RUNNABLE状态,抢不到就变成BLOCKED状态
线程的初始状态 NEW
public class ThreadState {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("运行中的线程的状态:" + Thread.currentThread().getState());
}
});
System.out.println("没运行前线程的状态:" + thread.getState());
}
}

在代码中,我们创建了一个线程,但还没有运行,这时候它的线程状态为NEW,而当调用 start()方法后,线程状态又会改变
线程的运行状态 RUNNABLE
public class ThreadState {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("运行中的线程的状态:" + Thread.currentThread().getState());
}
});
System.out.println("没运行前线程的状态:" + thread.getState());
thread.start();
}
}

我们线程在运行中的代码打印的是RUNNABLE,为什么是RUNNABLE呢?RUNNABLE的意思是可运行的,它里面其实还包含了操作系统线程中的两种状态,一种是RUNNING,一种是READY。所以RUNNABLE可以表达两种状态当前线程是正在运行,另一种是线程运行中的时候CPU被调度去做别的事情而陷入等待(不是被阻塞,是CPU暂时还没分配给它),这时候线程的状态也是保持不变的。
线程的结束状态 TERMINATED
public class ThreadState {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("运行中的线程的状态:" + Thread.currentThread().getState());
}
});
System.out.println("没运行前线程的状态:" + thread.getState());
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("运行结束后,线程的状态:" + thread.getState());
}
}
上面的线程是运行结束后,才打印它的状态,这输出可以说明,线程结束后,他的状态为 TERMINATED,其实还有另一种情况,会导致线程处于TERMINATED状态
public class ThreadState {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("运行中的线程的状态:" + Thread.currentThread().getState());
throw new RuntimeException();
}
});
System.out.println("没运行前线程的状态:" + thread.getState());
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程被打断后的状态为:" + thread.getState());
}
}

我们在上面的代码抛出了一个 RuntimeException异常,促使线程被迫停止,并在异常结束后打印了线程的状态,还是如线程正常停止后的状态一样是TERMINATED。
即当线程正常运行结束后,或者线程运行期间出现了一个未捕获异常,终止了 run()方法,而最终导致停止,线程的状态都会是 TERMINATED
线程没有抢到 synchronized锁后的状态 BLOCKED
public class ThreadState implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "进来了");
blockedState();
}
public static void main(String[] args) {
ThreadState runnable = new ThreadState();
Thread thread1 = new Thread(runnable, "线程1");
Thread thread2 = new Thread(runnable, "线程2");
thread1.start();
thread2.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程1此时的状态为:" + thread1.getState());
System.out.println("线程2此时的状态为:" + thread2.getState());
}
public synchronized void blockedState() {
while (true) {}
}
}

我们实现Runnable接口,并实现 run()方法,在 run()方法中调用一个被synchronized的方法,并在方法中让调用方法的线程陷入死循环,这时候进去的第一个线程会陷入死循环,第二个线程会来获取 synchronized的 monitor锁,而锁被前一个线程持有,所以第二个线程陷入阻塞状态
注:只有进入被 synchronized修饰的方法或方法,其它未能获取到 monitor锁的线程才会进入阻塞状态。
上面进入死循环的线程的状态为什么是RUNNABLE?
因为这个线程一直在运行中,只是运行的内容是无穷无尽,不会停止而已,所以它的线程状态为 RUNNABLE
线程进入等待状态的 WAITING
public class ThreadState implements Runnable {
Object lock = new Object();
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "进来了");
synchronized (lock){
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ThreadState runnable = new ThreadState();
Thread thread = new Thread(runnable);
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程此时的状态为:" + thread.getState());
}
}

上面定义了一个 Object的锁,而后在 run()方法中,调用这个Object对象的 wait()方法,让整个线程进入等待状态并释放掉对象的锁,后面由于没有使用notify()/notifyAll()方法,这个线程会一直等待中,不会结束。这个时候,线程的状态为 WAITING
让线程状态变为WAITING状态的方法还有几个常见的,代码就不演示了
- 对象.wait(),wait()方法比如得在 synchronized修饰的方法或代码块中使用
- 线程.join(),等待其它线程的完成,这时候也会进入WAITING状态
- LockSupport.park():这个是在网上大家都这么说的,我也没用过
线程进入时间倒计时等待的 TIMED_WAITING
public class ThreadState implements Runnable {
Object lock = new Object();
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "进来了");
synchronized (lock){
try {
lock.wait(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ThreadState runnable = new ThreadState();
Thread thread = new Thread(runnable);
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程此时的状态为:" + thread.getState());
}
}

相比于测试WAITING代码,我只是修改了一行,就是wait(),在里面给它设置了等待5秒,如果超时了,则会放弃等待继续执行
注:跟上面不同的有,线程虽然进入等待状态,就算不被唤醒,也不会永久等待下去,当设置的超时时间到时,线程就会继续执行下去
让线程状态变为TIMED_WAITING状态的方法还有几个常见的
- 对象.wait(时间戳),wait()方法比如得在 synchronized修饰的方法或代码块中使用
- 线程.join(时间戳),等待其它线程的完成,这时候也会进入WAITING状态
- LockSupport.parkUntil(时间戳):这个是在网上大家都这么说的,我也没用过
- LockSupport.parkNanos(时间戳):这个是在网上大家都这么说的,我也没用过
- 线程.sleep(时间戳):让线程休眠
欢迎大家关注下个人的「公众号」:独醉贪欢
本文详细探讨了Java并发编程中线程的多种状态,包括NEW、RUNNABLE、TERMINATED、BLOCKED、WAITING和TIMED_WAITING,并通过实例解释了状态之间的转换,帮助理解线程在不同条件下的行为。

被折叠的 条评论
为什么被折叠?



