学并发编程的时候,我们不仅仅要知道如何创建线程、停止线程,还要知道线程的各种状态,还有线程之间切换的顺序问题,以便我们在寻找问题的时候,更容易解决问题
当线程调用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());
}
}
线程的运行状态 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) {}
}
}
注:只有进入被 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());
}
}
让线程状态变为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(时间戳):让线程休眠
欢迎大家关注下个人的「公众号」:独醉贪欢