摘要: 原创出处 https://studyidea.cn 「公众号:程序通事 」欢迎关注和转载,保留摘要,谢谢!

使用 Java 阻塞 I/O 模型读取数据,将会导致线程阻塞,线程将会进入休眠,从而让出 CPU 的执行权,直到数据读取完成。这个期间如果使用 jstack 查看线程状态,却可以发现Java 线程状态是处于 RUNNABLE,这就和上面说的存在矛盾,为什么会这样?

上面的矛盾其实是混淆了操作系统线程状态与 Java 线程状态。这里说的线程阻塞进入休眠状态,其实是操作系统层面线程实际状态。而我们使用 jstack 查看的线程状态却是 JVM 中的线程状态。

线程是操作系统中一种概念,Java 对其进行了封装,Java 线程本质上就是操作系统的中线程,其状态与操作系统的状态大致相同,但还是存在一些区别。

下面首先来看我们熟悉的 Java 线程状态。

Java 线程状态

Java 线程状态定义在 Thread.State 枚举中,使用 thread#getState 方法可以获取当前线程的状态。

Thread.State 状态如下图:

可以看到 Java 线程总共存在 6 中状态,分别为:

NEW(初始状态)

RUNNABLE(运行状态)

BLOCKED(阻塞状态)

WATTING(等待状态)

TIMED_WAITING(限时等待状态)

TERMINATED(终止状态)

NEW(初始状态)与 RUNNABLE(运行状态)

每个使用 new Thread() 刚创建出线程实例状态处于 NEW 状态,一旦调用 thread.start(),线程状态将会变成 RUNNABLE。

RUNNABLE(运行状态) 与 BLOCKED(阻塞状态)

RUNNABLE 状态的线程在进入由 synchronized修饰的方法或代码块前将会尝试获取一把隐式的排他锁,一旦获取不到,线程状态将会变成 BLOCKED,等待获取锁。一旦有其他线程释放这把锁,线程成功抢到该锁,线程状态就将会从 BLOCKED 转变为 RUNNABLE 状态。

RUNNABLE(运行状态) 与 WATTING(等待状态)

处于 WATTING 状态的线程将会一直处于无限期的等待状态,需要等待其他线程唤醒。总共存在三种方法将会使线程从 RUNNABLE 变成 WATTING。

Object#wait

线程在获取到 synchronized 隐式锁后,显示的调用 Object#wait()方法。这种情况下该线程将会让出隐式锁,一旦其他线程获取到该锁,且调用了 Object.notify() 或object.notifyAll(),线程将会唤醒,然后变成 RUNNABLE。

Thread#join

join方法是一种线程同步方法。假设我们在 main 方法中执行 Thread A.join() 方法,main 线程状态就会变成 WATTING。直到 A 线程执行完毕,main 线程才会再变成 RUNNABLE。

LockSupport#park()

LockSupport 是 JDK 并发包里重要对象,很多锁的实现都依靠该对象。一旦调用 LockSupport#park(),线程就将会变为 WATTING 状态。如果需要唤醒线程就需要调用 LockSupport#unpark,然后线程状态重新变为 RUNNABLE。

RUNNABLE(运行状态) 与 TIMED_WAITING(限时等待状态)

TIMED_WAITING 与 WATTING 功能一样,只不过前者增加限时等待的功能,一旦等待时间超时,线程状态自动变为 RUNNABLE。以下几种情况将会触发这种状态:

Thread#sleep(long millis)

占有 synchronized 隐式锁的线程调用 Object.wait (long timeout) 方法

Thread#join (long millis)

LockSupport#parkNanos (Object blocker, long deadline)

LockSupport#parkUntil (long deadline)

RUNNABLE(运行状态)与 TERMINATED(终止状态)

线程一旦执行结束或者线程执行过程发生异常且未正常捕获处理,状态都将会自动变成 TERMINATED。

Java 线程 6 种状态看起来挺复杂的,但其实上面 BLOCKED,WATTING,TIMED_WAITING,都会使线程处于休眠状态,所以我们将这三类都归类为休眠状态。这么分类的话,Java 线程生命周期就可以简化为下图:

通用操作系统线程状态

上面讲完 Java 系统的线程状态,我们来看下通用操作系统的线程状态。操作系统线程状态可以分为初始状态,可运行状态,运行状态,休眠状态以及终止状态,如下图:

这 5 中状态详细情况如下:

初始状态,这时候线程刚被创建,还不能分配 CPU 。

可运行状态,线程等待系统分配 CPU ,从而执行任务。

运行状态,操作系统将 CPU 分配给线程,线程执行任务。

休眠状态,运行状态下的线程如果调用阻塞 API,如阻塞方式读取文件, 线程状态就将变成休眠状态。这种情况下,线程将会让出 CPU 使用权。休眠结束,线程状态将会先变成可运行状态。

线程执行结束或者执行过程发生异常将会使线程进入终止状态,这个状态下线程使命已经结束。

对比两者线程状态

比较 Java 线程与操作系统线程,可以发现 Java 线程状态没有可运行状态。也就是说 Java 线程 RUNNABLE 状态包括了操作系统的可运行状态与运行状态。一个处于 RUNNABLE 状态 Java 线程,在操作系统层面状态可能为可运行状态,正在等待系统分配 CPU 使用权。

另外 Java 线程细分了操作系统休眠状态,分成了 BLOCKED,WATTING,TIMED_WAITING 三种。

当线程调用阻塞式 API,线程进入休眠状态,这里指的是操作系统层面的。从 JVM 层面,Java 线程状态依然处于 RUNNABLE 状态。JVM 并不关心操作系统线程实际状态。从 JVM 看来等待 CPU 使用权(操作系统线程状态为可运行状态)与等待 I/O (操作系统线程状态处于休眠状态)没有区别,都是在等待某种资源,所以都归入 RUNNABLE 状态。

其他 Java 线程状态与操作线程状态类似。

java runnable wait_面试官:都说阻塞 I/O 模型将会使线程休眠,为什么 Java 线程状态却是 RUNNABLE?...相关推荐

  1. 「从源码中学习」面试官都不知道的Vue题目答案

    前言 当回答面试官问及的Vue问题,我们除了照本宣科的回答外,其实还可以根据少量的源码来秀一把,来体现出你对Vue的深度了解. 本文会陆续更新,此次涉及以下问题: "new Vue()做了什 ...

  2. 程序员面试快手后感慨:你们经历过绝望吗?三个面试官都是清华的

    一名程序员在面试完快手后如此感叹:快手的要求确实高,比阿里难进100倍,三个面试官都是清华的,全是问的acm和算法题. 所谓同行相轻,马上又网友评论:题刷得好不代表解决问题能力强,面试一般考一两个考察 ...

  3. 视频面试,面试官都在注意些什么?

    受疫情的影响,"视频面试"功能成功解了企业避免"面对面"招聘的燃眉之急,也为求职者也带来了极大的便利. 随着视频面试的热度不断攀升,人们讨论的话题和热度自然也转 ...

  4. 面试官都在问 | Linux命令mpstat详解

    面试官都在问 | Linux命令mpstat详解 1. mpstat的基本用法 mpstat的全称为Multiprocessor Statistics,是一款常用的多核CPU性能分析工具,用来实时查询 ...

  5. 吃透这JAVA并发十二核心,面试官都得对你刮目相看

    1.HashMap 面试第一题必问的 HashMap,挺考验Javaer的基础功底的,别问为啥放在这,因为重要!HashMap具有如下特性: HashMap 的存取是没有顺序的. KV 均允许为 NU ...

  6. java 获取文件大小_阿里Java后端开发面经,面试官都替我感到绝望

    点关注,不迷路:持续更新Java相关技术及资讯!!! 内容源于群友投稿!记录一次阿里Java后端开发面经,分享给大家,感谢支持! 前言 秋招面试的第一家公司,也是第一次面试,真的超级紧张,从自我介绍到 ...

  7. 阿里Java后端开发面经,面试官都替我感到绝望

    前言 秋招面试的第一家公司,也是第一次面试,真的超级紧张,从自我介绍到项目介绍再到问题回答,面试表现真的是灾难级~ 由于我笔试做的还行,一面的时候准备的都是项目相关的问题,Java基础和框架相关的就没 ...

  8. 快手Java后台三面,意向已拿,面试官都问了些啥?

    快手的面试挺有挑战性的感觉哈哈哈哈,不过我觉得挺有意思的,感觉啥都能问到.(二面是10天前约的面试,差点要忘了)然后是HR面,昨天就收到offer 一面二面啥的我都忘记具体的了,就简单的总结一下 1基 ...

  9. 快手三面(Java岗位),offer已拿,面试官都问了些啥?

    快手的面试挺有挑战性的感觉哈哈哈哈,不过我觉得挺有意思的,感觉啥都能问到.(二面是10天前约的面试,差点要忘了)然后是HR面,昨天就收到offer 一面二面啥的我都忘记具体的了,就简单的总结一下 1基 ...

最新文章

  1. Kubernetes基于Metrics Server的HPA
  2. [Hadoop]Hive-1.2.x安装配置+Mysql安装
  3. boost::histogram::detail::argument_traits用法的测试程序
  4. python中用来回溯异常的模块_python学习笔记(异常)
  5. 改变WCF service location的 hostName
  6. HDOJ 5184 Brackets 卡特兰数扩展
  7. python:函数的参数传递方法演示
  8. 【转】OAuth的改变
  9. redis的简单操作
  10. 用亿图软件怎么画数据模型图?
  11. php实现室内地图导航,叠加室内地图-室内地图-示例中心-JS API 示例 | 高德地图API...
  12. 面试一个应届生,从不起眼到令人刮目相看
  13. c语言怎么打尖括号,怎么在word中利用键盘快速输入尖括号
  14. 【iMessage苹果推信家庭推】位置推通过苹果实现iMessage群发的Apple script脚本代码如下: tell application “Messages” set csvDatator
  15. FullCalendar-vue demo例子
  16. 文件查重删除,继续完善及修改上篇内容
  17. java 图片宽高_[Java]获取图片高和宽
  18. python 线程安全队列_Python实现线程安全队列
  19. 无人机右手定则以及角度大小方向粗判断
  20. 关于AJAX开发技巧的想法

热门文章

  1. python语言入门编程猫-编程猫推出海龟编程器,打造Python教育产品矩阵
  2. python读取大文件-使用Python读取大文件的方法
  3. python 网站文件下载-python从网站上下载东西
  4. python基础常用语句-Python基础6—常用语句
  5. 把LabelImg标注的YOLO格式标签转化为VOC格式标签 和 把VOC格式标签转化为YOLO格式标签
  6. opencv python 中cv2.putText()函数的用法
  7. LeetCode Clone Graph(搜索问题)
  8. spoj Simple Average
  9. MyBatis Generator 详解
  10. asio中的socket相关service的关系图