1 | /** |
在 ConcurrentHashMap
的 initTable
方法中,可以看到对该方法的使用,源码如下:
1 | /** |
可以看出,若当前线程判断 table
当前时刻已经在被其他线程进行初始化时,则调用 Thread.yield()
提示调度程序当前线程愿意放弃对当前处理器的使用权,以尝试降低对 CPU 的争用。
1 | /** |
在 ConcurrentHashMap
的 initTable
方法中,可以看到对该方法的使用,源码如下:
1 | /** |
可以看出,若当前线程判断 table
当前时刻已经在被其他线程进行初始化时,则调用 Thread.yield()
提示调度程序当前线程愿意放弃对当前处理器的使用权,以尝试降低对 CPU 的争用。
JVM 中的线程可能处于以下状态:
JVM 中的线程在任意时刻只能处于一种状态。这些状态仅是 JVM 虚拟机中的线程状态,并不反应操作系统的线程状态。
记录这个问题是因为之前在我们的监控服务中经常探测到持续的 RUNNABLE
线程,经过定位,发现是我们自身的用于监控堆转储文件的线程,其实在操作系统中的状态并不是 R
,即并不是运行中或位于运行队列中,我们用一个例子来说明,在我们的线程转储中,经常发现如下的线程数据:
1 | "Thread-5" #16 daemon prio=5 os_prio=0 tid=0x00007f4920006800 nid=0x2d runnable [0x00007f49338e9000] |
该方法在 JVM 线程转储中一直处于 RUNNABLE
状态,但是,根据 nid=0x2d
我们转换出对应的 Linux 轻量级进程 id:45
通过如下命令查询轻量级进程状态(其中的 1 为 JVM 进程的 id):
1 | cat /proc/1/task/45/status | grep 'State:' |
可以得到以下输出:
1 | State: S (sleeping) |
得到的状态为 S
,在 Linux 文档中对应的解释为:interruptible sleep (waiting for an event to complete)
,这也验证了 Java 文档中的说法,JVM 中的线程状态并不反应操作系统中的线程状态。
同理,最常见的 Netty 执行 Epoll 的线程栈帧:
1 | "NettyClientWorker-4-7" #424 daemon prio=5 os_prio=0 tid=0x00007f28080ba000 nid=0x1b5 runnable [0x00007f27f2341000] |
其在 JVM 中的线程状态为 RUNNABLE
, 在操作系统级别的状态也为 S (sleeping)
。
Thread.State (Java Platform SE 8 )
ps(1) - Linux manual page
Processes and Threads (The Java™ Tutorials > Essential Java Classes > Concurrency)
关于 Tomcat 的类加载器层次,我之前也只是看过文档中的介绍,并未深入理解,直到一次问题排查,对其有了更深入的理解,本文作简要记录。
在一次处理 java.sql.DriverManager
相关的问题时,看到 DriverManager 文档中有以下描述:
Applications no longer need to explicitly load JDBC drivers using Class.forName(). Existing programs which currently load JDBC drivers using Class.forName() will continue to work without modification.
于是果断把一个数据源工具类中的 Class.forName()
方法调用进行了移除。原实现:
1 | package me.tianshuang.util; |
1 | package me.tianshuang; |
以上代码使用了双括号初始化,其中外层那一对括号创建了一个匿名内部类,里层的那一对括号是一个实例初始化块。对于上面这一段源码,进行编译后我们可以在目录看到两个 class
文件,分别是 DoubleBraceTest.class
与 DoubleBraceTest$1.class
,其中 DoubleBraceTest$1.class
是我们定义的 HashMap
类的匿名子类,其反编译源码如下:
1 | // |
1 | /** |
该 native
方法在我开发 Java Agent 的过程中进行了调试,发现对于满足实现关系的类,如果不是由相同的类加载器加载,则会返回 false
。