线程--Java线程的主要状态及转换方法

一、操作系统中线程的状态转换
在现在的操作系统中,线程是被视作为轻量级进程的,所以操作系统线程的状态和操作系统进程的状态是一致的。

在这里插入图片描述

二、Java线程的6个状态

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

1.NEW

处于NEW状态的线程,代表线程创建成功,但并未启动。这里的未启动,指的是还没有调用start()方法。

代码示例如下:

@Test
    public void  testOne(){
        Thread thread = new Thread("test");
        System.out.println(thread.getState());
    }
    //输出内容:  NEW

针对start()的两个问题:
1.反复调用同一个线程的start()方法是否可行?
2.假如一个线程的状态为TERMINATED状态了,再次调用这个线程的start()是否可行?

start()方法的源码如下:

public synchronized void start() {
    if (threadStatus != 0)
        throw new IllegalThreadStateException();
    group.add(this);
    boolean started = false;
    try {
        start0();
        started = true;
    } finally {
        try {
            if (!started) {
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {
        }
    }
}

在该方法中有一个threadStatus 变量,当threadStatus不为0的时候会抛出异常终止方法的执行。

下面的 start0(); 是一个native方法,我们没有办法看到在这里面的操作。

可以通过打断点去看两次start()方法的调用threadStatus的值。

代码示例:

@Test
public void testStartMethod() {
    Thread thread = new Thread(() -> {});
    thread.start(); // 第一次调用
    thread.start(); // 第二次调用
}

通过断点可以看到

第一次调用时threadStatus的值是0。
第二次调用时threadStatus的值不为0。

然后再来看查看线程状态的源码:

public State getState() {
        // get current thread state
        return sun.misc.VM.toThreadState(threadStatus);
    }

--------------------------
public static State toThreadState(int var0) {
        if ((var0 & 4) != 0) {
            return State.RUNNABLE;
        } else if ((var0 & 1024) != 0) {
            return State.BLOCKED;
        } else if ((var0 & 16) != 0) {
            return State.WAITING;
        } else if ((var0 & 32) != 0) {
            return State.TIMED_WAITING;
        } else if ((var0 & 2) != 0) {
            return State.TERMINATED;
        } else {
            return (var0 & 1) == 0 ? State.NEW : State.RUNNABLE;
        }
    }

threadState的值为2的时候,线程的状态为TERMINATED。

所以通过分析源码得出结论:
两个 问题都是不可行的,线程在第一次调用start()方法后,变量threadState的值就会发生改变,即(threadState!=0),所以当线程再次调用start()方法的时候会抛出异常。

2.RUNNABLE

RUNNABLE状态代表线程正在执行中

我们可以通过源码注释看下Java中线程的RUNNABLE状态解释,如下所示:

/**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
        RUNNABLE,

由上可以看到:
处于RUNNABLE状态的线程可能在Java虚拟机中正在运行,也可能在等待其他的资源。

Java线程的RUNNABLE状态其实是包括了传统操作系统线程的ready和running两个状态的

3.BLOCKED

阻塞状态,处于阻塞状态的线程正等待锁的释放然后进入同步代码区内执行。

举个生活中的例子,A和B去银行窗口办理业务,A先办理,所以此时A先进入同步代码区域处理,
并拿到了锁。B需要等待A办理完业务离开业务窗口,释放了锁后,B才能进入同步代码区域。

4.WAITING

等待状态,处于WAITING状态的线程想要转换成RUNNABLE状态需要其他线程唤醒。

进入WAITING状态可通过如下三个方法:

Object.wait():使当前线程处于等待状态直到另一个线程唤醒它;
Thread.join():等待线程执行完毕,底层调用的是Object实例的wait方法;
LockSupport.park():除非获得调用许可,否则禁用当前线程进行线程调度。

5.TIMED_WAITING

超时等待状态。线程等待一个具体的时间,时间到后会被自动唤醒。

调用如下方法会使线程进入超时等待状态:

Thread.sleep(long millis):使当前线程睡眠指定时间;
Object.wait(long timeout):线程休眠指定时间,等待期间可以通过notify()/notifyAll()唤醒;
Thread.join(long millis):等待当前线程最多执行millis毫秒,如果millis为0,则会一直执行;
LockSupport.parkNanos(long nanos): 除非获得调用许可,否则禁用当前线程进行线程调度指定时间;
LockSupport.parkUntil(long deadline):同上,也是禁止线程进行调度指定时间;

6.TERMINATED

终止状态。表示线程已执行完毕。

三、线程状态的转换
转换图如下所示:
在这里插入图片描述

阻塞分为以下三种情况:

等待阻塞:通过调用线程的wait()方法,让线程等待某工作的完成。

同步阻塞:线程在获取synchronized同步锁失败(因为锁被其他线程占用),它会进入同步阻塞状态。

其他阻塞:通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或超时、或者I/O处理完毕时,线程重新转入就绪状态。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值