为什么Java线程没有Running状态?( 三 )


// 确保run已经得到执行
Thread.sleep(100);
// 状态为RUNNABLE
assertThat(t.getState()).isEqualTo(Thread.State.RUNNABLE);
}
在最后的语句上加一断点,监控上也反映了这一点:

为什么Java线程没有Running状态?

文章插图
网络阻塞时同理,比如socket.accept,我们说这是一个“阻塞式(blocked)”式方法,但线程状态还是 RUNNABLE 。
@Test
public void testBlockedSocketState() throws Exception {
Thread serverThread = new Thread(new Runnable() {
@Override
public void run() {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(10086);
while (true) {
// 阻塞的accept方法
Socket socket = serverSocket.accept();
// TODO
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}, "socket线程"); // 线程的名字
serverThread.start();
// 确保run已经得到执行
Thread.sleep(500);
// 状态为RUNNABLE
assertThat(serverThread.getState()).isEqualTo(Thread.State.RUNNABLE);
监控显示:
为什么Java线程没有Running状态?

文章插图
当然,Java 很早就引入了所谓 nio(新的IO)包,至于用 nio 时线程状态究竟是怎样的,这里就不再一一具体去分析了 。
 
至少我们看到了,进行传统上的 IO 操作时,口语上我们也会说“阻塞”,但这个“阻塞”与线程的 BLOCKED 状态是两码事!
如何看待RUNNABLE状态? 
首先还是前面说的,注意分清两个层面:
为什么Java线程没有Running状态?

文章插图
虚拟机是骑在你操作系统上面的,身下的操作系统是作为某种资源为满足虚拟机的需求而存在的:
当进行阻塞式的 IO 操作时,或许底层的操作系统线程确实处在阻塞状态,但我们关心的是 JVM 的线程状态 。
 
JVM 并不关心底层的实现细节,什么时间分片也好,什么 IO 时就要切换也好,它并不关心 。
 
前面说到,“处于 runnable 状态下的线程正在* Java 虚拟机中执行,但它可能正在等待*来自于操作系统的其它资源,比如处理器 。”
JVM 把那些都视作资源,cpu 也好,硬盘,网卡也罢,有东西在为线程服务,它就认为线程在“执行” 。
处于 IO 阻塞,只是说 cpu 不执行线程了,但网卡可能还在监听呀,虽然可能暂时没有收到数据:
 
就好比前台或保安坐在他们的位置上,可能没有接待什么人,但你能说他们没在工作吗?
 
所以 JVM 认为线程还在执行 。而操作系统的线程状态是围绕着 cpu 这一核心去述说的,这与 JVM 的侧重点是有所不同的 。
前面我们也强调了“Java 线程状态的改变通常只与自身显式引入的机制有关”,如果 JVM 中的线程状态发生改变了,通常是自身机制引发的 。
 
比如 synchronize 机制有可能让线程进入BLOCKED 状态,sleep,wait等方法则可能让其进入 WATING 之类的状态 。
 
它与传统的线程状态的对应可以如下来看:
为什么Java线程没有Running状态?

文章插图
RUNNABLE 状态对应了传统的 ready,running 以及部分的 waiting 状态 。
 
作者:国栋 my.oschina.NET/goldenshaw/blog/705397
 
公众号“Java精选”所发表内容注明来源的,版权归原出处所有(无法查证版权的或者未注明出处的均来自网络,系转载,转载的目的在于传递更多信息,版权属于原作者 。如有侵权,请联系,笔者会第一时间删除处理!
最近有很多人问,有没有读者交流群!加入方式很简单,公众号Java精选,回复“加群”,即可入群!


推荐阅读