线程的各种状态和顺序

122 阅读5分钟

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

在这里插入图片描述

当线程调用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(时间戳):让线程休眠

欢迎大家关注下个人的「公众号」:独醉贪欢