Linux 上的 Java 线程优先级
最近看了一篇关于 Java 在 Linux 上设置线程优先级的文章, 受益良多. 原来写了这么多年 Java 代码, 线程优先级在 Linux 上竟然是默认竟然是无效的. 这个网站可能在国内无法访问:
Thread Priority in Linux and Java
大致意思是:
Java 有个 Flag 是: -XX:ThreadPriorityPolicy. 它的值默认是 0, 还有另外一个值是 1. 对着 2 个值的解释是:
0 : Normal.
VM chooses priorities that are appropriate for normal
applications. On Solaris NORM_PRIORITY and above are mapped
to normal native priority. Java priorities below
NORM_PRIORITY map to lower native priority values. On
Windows applications are allowed to use higher native
priorities. However, with ThreadPriorityPolicy=0, VM will
not use the highest possible native priority,
THREAD_PRIORITY_TIME_CRITICAL, as it may interfere with
system threads. On Linux thread priorities are ignored
because the OS does not support static priority in
SCHED_OTHER scheduling class which is the only choice for
non-root, non-realtime applications.
1 : Aggressive.
Java thread priorities map over to the entire range of
native thread priorities. Higher Java thread priorities map
to higher native thread priorities. This policy should be
used with care, as sometimes it can cause performance
degradation in the application and/or the entire system. On
Linux this policy requires root privilege.
所以, 要想 Java 的优先级在 Linux 上生效, 要这么做(既要 sudo 又要设置 flag):
sudo java -XX:ThreadPriorityPolicy=1 ThreadPrioTest
就能看到下面的优先级输出:
supra@suprabox:~$ ps -l -m -p $(pgrep java)
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
4 - 0 30388 30387 99 - - - 2033328 - pts/2 00:03:00 java
1 S 0 - - 62 84 4 - - - - 00:00:14 -
1 S 0 - - 66 83 3 - - - - 00:00:15 -
1 S 0 - - 68 82 2 - - - - 00:00:15 -
1 S 0 - - 74 81 1 - - - - 00:00:17 -
1 S 0 - - 78 80 0 - - - - 00:00:17 -
1 S 0 - - 76 79 -1 - - - - 00:00:17 -
1 S 0 - - 79 78 -2 - - - - 00:00:18 -
1 S 0 - - 85 77 -3 - - - - 00:00:19 -
1 S 0 - - 88 76 -4 - - - - 00:00:20 -
1 S 0 - - 90 75 -5 - - - - 00:00:20 -
上面的测试文件内容:
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.Random;
public class ThreadPrioTest {
public static void main(String[] args) throws InterruptedException {
Runnable runnable = new Runnable() {
public void run() {
StringBuffer sb = new StringBuffer("");
while (true) {
Random r = new Random();
sb.append(r.nextDouble());
sb.setLength(300);
sb.trimToSize();
}
}
};
for (int i = 0; i < 10; i++) {
Thread t = new Thread(runnable, "ThreadTest_ " + i);
t.setPriority(i+1);
t.start();
}
ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean();
ThreadInfo[] threadInfos = threadMxBean.dumpAllThreads(false, false);
String name = null;
for (int i = 0; i < 1000; i++) {
System.out.println();
for (ThreadInfo info : threadInfos) {
name = info.getThreadName();
if (name.contains("ThreadTest")) {
System.out.println(name + " " + threadMxBean.getThreadCpuTime(info.getThreadId()));
}
}
Thread.sleep(30000);
}
}
}
运行的结果(可以看到占用时间的差别):
supra@suprabox$ sudo java -XX:ThreadPriorityPolicy=1 ThreadPrioTest
ThreadTest_ 0 31115073
ThreadTest_ 1 88458982
ThreadTest_ 2 57653703
ThreadTest_ 3 47742366
ThreadTest_ 4 87852759
ThreadTest_ 5 81910285
ThreadTest_ 6 87854949
ThreadTest_ 7 74596281
ThreadTest_ 8 73344747
ThreadTest_ 9 79761175
...
ThreadTest_ 0 94775603625
ThreadTest_ 1 100380714690
ThreadTest_ 2 100932887535
ThreadTest_ 3 108438013681
ThreadTest_ 4 113013836327
ThreadTest_ 5 118102801890
ThreadTest_ 6 121683982580
ThreadTest_ 7 127791024493
ThreadTest_ 8 130891651909
ThreadTest_ 9 134574994529
如果你是在一个有大于 10 个 CPU 核的机器上跑这个测试, 可能结果并不是这样, 因为他们又足够的 CPU, 所以各个优先级的线程使用 CPU 差别不是很大. 所以线程优先级只有在 CPU 不够用的机器上才比较明显.
另外 java 里面关于线程优先级的 flags:
supra@suprabox:~$ java -XX:+PrintFlagsFinal -version | grep riori
intx CompilerThreadPriority = -1 {product} {default}
intx JavaPriority10_To_OSPriority = -1 {product} {default}
intx JavaPriority1_To_OSPriority = -1 {product} {default}
intx JavaPriority2_To_OSPriority = -1 {product} {default}
intx JavaPriority3_To_OSPriority = -1 {product} {default}
intx JavaPriority4_To_OSPriority = -1 {product} {default}
intx JavaPriority5_To_OSPriority = -1 {product} {default}
intx JavaPriority6_To_OSPriority = -1 {product} {default}
intx JavaPriority7_To_OSPriority = -1 {product} {default}
intx JavaPriority8_To_OSPriority = -1 {product} {default}
intx JavaPriority9_To_OSPriority = -1 {product} {default}
intx ThreadPriorityPolicy = 0 {product} {default}
bool ThreadPriorityVerbose = false {product} {default}
bool UseThreadPriorities = true {pd product} {default}
intx VMThreadPriority = -1 {product} {default}
openjdk version "11.0.11" 2021-04-20
OpenJDK Runtime Environment (build 11.0.11+9-Ubuntu-0ubuntu2.18.04)
OpenJDK 64-Bit Server VM (build 11.0.11+9-Ubuntu-0ubuntu2.18.04, mixed mode, sharing)
关于之前 Java 里面关于那个 flag 的 bug:
http://www.akshaal.info/2008/04/javas-thread-priorities-in-linux.html
关于 Java 线程优先级的另外一个问答:
https://stackoverflow.com/questions/46936170/cassandra-and-java-9-threadprioritypolicy-42-is-outside-the-allowed-range