学习小记 -- 终于把线程状态流转理清楚了

目录

最简单的周期

进阶:

进进阶:

park/unpark

TIMED_WAITING/Thread.sleep(long)

总结:


线程状态肯定是有线程才会做讨论的,没有线程的话更不用谈论其状态一说,所以我们可以从线程创建开始说起。

最简单的周期

当我们做Thread t = new Thread()时,新线程Thread类中有一个私有变量threadStatus,这个变量就表示线程的状态,此时线程状态为初始态,通过器内部枚举类做映射,

 

private volatile int threadStatus = 0;

查看其构造方法:

public Thread() {
    init(null, null, "Thread-" + nextThreadNum(), 0);
}

private void init(ThreadGroup g, Runnable target, String name,
                  long stackSize) {
    init(g, target, name, stackSize, null, true);
}

private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
    ...
    this.group = g;
    this.daemon = parent.isDaemon();
    this.priority = parent.getPriority();
    ...
    tid = nextThreadID();
}

可以看到,构造方法中无非是给属性做了赋值操纵,并没有对state做修改。

下一步,调用thread.start()方法。

在这个方法里最终会调用

private native void start0();

这是一个本地native方法,具体实现需要查看jvm源码,这里就不做展示了,直接贴出:

hotspot/src/os/linux/vm/os_linux.cpppthread_create(...);

即调用了unix 创建线程的方法:pthread_create。linux 操作系统,是没有所谓的刚创建但没启动的线程这种说法的,创建即刻开始运行,所以现在线程便是一个RUNNABLE状态

当一个线程执行完毕,线程状态会变成TERMINATED

以上就是最简单的生命周期。初始--运行--终止

进阶:

假设有两个线程thread1,thread2,都要执行同一个synchronized块,thread1获取锁后拿住不放,thread2在进入synchronized块后,会阻塞,线程状态会变成BLOCKED

进进阶:

1. 当一个线程中,有lock.wait()方法被调用,会发生下面三件事:

  1. 线程释放锁Lock。
  2. 线程状态变成 WAITING。
  3. 线程进入 lock 对象的等待队列。

直到另一个线程调用同一个对象的notify/notifyAll 方法,当前线程才会被唤醒,从等待队列中移出,并从 WAITING 状态返回 RUNNABLE 状态。但这里要注意的是,被唤醒后任需要先抢锁,只有抢锁成功才会变为RUNNABLE 状态,否则还是变为BLOCKED。

2. 当主线中执行join()方法时,主线程线程状态变成WAITING,当自线程执行结束,主线程才会返回RUNNABLE 状态。

join的本质就是执行了wait,锁对象就是 Thread 对象本身。join执行完毕后,jvm会自动调用notifyAll()方法。

park/unpark

当一个线程调用LockSupport.park(),该线程状态会从 RUNNABLE 变成 WAITING;另一个线程调用LockSupport.unpark(Thread 刚刚的线程),刚刚的线程会从 WAITING 回到 RUNNABLE。

prak和unpark的原理这里就不做详解了,以后有机会再讲。

TIMED_WAITING/Thread.sleep(long)

如果在上面导致线程变成 WAITING 状态的那些方法都加一个超时参数,就变成了将线程变成 TIMED_WAITING 状态的方法了。

sleep方法可以让仅仅让线程挂起,等待超时后再呗唤醒:

 

总结:

问:调用 jdk 的 Lock 接口中的 lock,如果获取不到锁,线程将挂起,此时线程的状态是什么呢?

有人觉得应该和 synchronized 获取不到锁的效果一样,是变成 BLOCKED 状态?

不过如果其实jdk 中锁的实现,是基于 AQS 的,而 AQS 的底层,是用 park 和 unpark 来挂起和唤醒线程,所以应该是变为 WAITING 或 TIMED_WAITING 状态。

问:调用阻塞 IO 方法,线程变成什么状态?

比如 socket 编程时,调用如 accept(),read() 这种阻塞方法时,线程处于什么状态呢?

答案是处于 RUNNABLE 状态,但实际上这个线程是得不到运行权的,因为在操作系统层面处于阻塞态,需要等到 IO 就绪,才能变为就绪态。

但是在 Java 层面,JVM 认为等待 IO 与等待 CPU 执行权,都是一样的。

 

 

 

参考:https://mp.weixin.qq.com/s/kjeWEXJfDz5pM3HLhYs9Xw

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值