多线程并发

Java线程状态和线程方法

2021-07-20  本文已影响0人  肥兔子爱豆畜子

线程状态

线程状态图

线程状态.png

上面是理论书本上的线程模型规定的线程状态,而实际上Java中线程的状态是怎么样的呢?

Java线程状态

线程状态定义在java.lang.Thread.State 中,是个枚举类型。

public enum State {
    NEW,
    RUNNABLE,
    BLOCKED,
    WAITING,
    TIMED_WAITING,
    TERMINATED;
}

一共是6种状态,与上文中的理论模型稍微有些调整:

  1. 由于无法完全控制由操作系统决定的线程得到CPU timeslice与否、Java中就将就绪和运行两种状态统称为RUNNABLE可执行。
  2. 而将阻塞状态细分为BLOCKED、WAITING、TIMED_WAITING三种。分别对应等待获取锁、获取锁之后将锁暂时释放而后等待通知重新竞争锁、以及sleep等几种情形。
  3. 剩下的新建与终止状态则与理论模型一致。
Java线程状态转移.png

如图是Java线程的各个状态,以及各个状态之间转换的方式。我们来过一下这个图。

以上介绍了Java线程的状态以及在各种状态间变化的线程方法,关于线程方法还有一个interrupt方法需要注意。本质上线程的interrupt()方法只是改变了线程内的一个中断标志位而已,并不是说这样就会导致这个线程因此阻塞或终止。许多方法比如引导线程进入TIMED_WAITING状态的一些个方法比如sleep,其内部是spin的,经由判断当前线程的中断标志位来确定spin是否应该停止,如果这时候调用了thread.interrupt(),线程内部会通过抛出InterruptedException来跳出spin从而执行完run而终止线程。另一方面,对于我们自己编写的线程spin逻辑,也可以使用这个中断标志位来达到停止线程的目的,效果相当于在线程间共享一个当作信号的volatile变量,比如:

    public static void main(String[] args) throws InterruptedException {
        
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                logger.info("t1子线程开始执行...");
                while(!Thread.currentThread().isInterrupted()) {
                    //logger.info("t1子线程还没被中断,继续执行");
                    /*
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }*/
                }
                logger.info("t1被中断了,跳出spin,执行完毕");
            }});
        
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                    logger.info("t2子线程将会在10秒后对t1子线程发起中断");
                    try {
                        TimeUnit.SECONDS.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                t1.interrupt();
            }});

        t1.start();
        t2.start();
        t1.join();
    }

输出结果:

[2021-07-20 15:48:08] - t2子线程将会在10秒后对t1子线程发起中断
[2021-07-20 15:48:08] - t1子线程开始执行...
[2021-07-20 15:48:18] - t1被中断了,跳出spin,执行完毕

需要提一下的是如果把上面的sleep那里的注释放开的话,大概率t2向t1发起中断的时候t1在sleep,这样t1会以throw InterruptedException的方式来响应这个中断,然后抛出异常之后会重置线程内部的中断标志位,这样t1的下一次while判断就会判断中断没有发生了,从而t1会继续执行。

上一篇 下一篇

猜你喜欢

热点阅读