Linux JVM实际上是否实现了线程优先级?

时间:2009-11-02 16:09:15

标签: java multithreading jvm thread-priority

编写一个快速的Java proggy以产生每个优先级的10个线程,并使用BigDecimals计算pi(4 * atan(1)方法),每个BigDecimals 500,000次,连接每个线程并报告run方法的已用时间。是的,可能不是最好的例子,但保持基本。

我知道Bug4813310

在C中做这件事并非易事,但是我们可以假设从未在Linux JVM上设置原生优先级吗?

$uname -r && grep bogomips /proc/cpuinfo
2.4.33.3
bogomips        : 4312.26
$java -version 2>&1 |head -1
Java version "1.6.0_01"
$javac T.java && java -Xmx32m -XX:+UseThreadPriorities T
1:3112
2:2636
3:2662
4:3118
5:2870
6:3319
7:3412
8:3304
9:3299
10:3069

看起来没有人会期待的偏差!那是在一台小型虚拟Linux机器上。也许只是Sun的?我们将尝试使用IBM J9 VM:

1:4091
2:4142
3:3957
4:3905
5:3984
6:3985
7:4130
8:4055
9:3752
10:4071

相比之下,总数看起来相当不错,但从线程优先级的角度来看,数字没有规模。

让我们尝试使用旧版Sun JVM在2.6内核上进行500k次迭代,其中一个常常加载的平均负载很少低于7:

$uname -r && grep bogomips /proc/cpuinfo
2.6.9-67.ELsmp
bogomips        : 3992.93
bogomips        : 3990.00
$java -version 2>&1 |head -1
java version "1.4.2_14"
$javac T.java && java -Xmx32m -XX:+UseThreadPriorities T
1:63200
2:64388
3:62532
4:58529
5:62292
6:64872
7:64885
8:64584
9:61653
10:61575

让我们在2.6内核的基础上尝试使用IBM的J9,因为更大的系统我会将迭代次数增加到2,000,000。

$uname -r && grep bogomips /proc/cpuinfo
2.6.9-78.ELsmp
bogomips        : 5989.03
bogomips        : 5985.03
bogomips        : 5985.01
bogomips        : 5985.02
bogomips        : 5984.99
bogomips        : 5985.02
bogomips        : 5984.99
bogomips        : 5985.02
$java -Xmx32m T # this is the IBM J9
1:1718
2:1569
3:1989
4:1897
5:1839
6:1688
7:1634
8:1552
9:2027
10:1522

有些好时光,但仍然没有明显的线程/流程优先级。

我们试试一个Windows框。我知道Windows有一个相当激进的线程优先级方案。任何高于正常的传闻都会消耗得更多。因此,让我们在每个线程中进行900,000次迭代:

C:\>java -version
java version "1.6.0_11"
C:\>java -Xmx32m T
1:12578
2:12625
3:11469
4:11453
5:10781
6:8937
7:10516
8:8406
9:9953
10:7391

我们正在寻找什么,不是吗?

所以Linux JVM显然没有线程优先级?我知道你不能真正在C中降低一个好的级别,但我会假设JVM工程师会想出如何保持一个低调的各种调度员。

3 个答案:

答案 0 :(得分:20)

好吧,让我们看一下the source

第2947行:

////////////////////////////////////////////////////////////////////////////////
// thread priority support

// Note: Normal Linux applications are run with SCHED_OTHER policy. SCHED_OTHER
// only supports dynamic priority, static priority must be zero. For real-time
// applications, Linux supports SCHED_RR which allows static priority (1-99).
// However, for large multi-threaded applications, SCHED_RR is not only slower
// than SCHED_OTHER, but also very unstable (my volano tests hang hard 4 out
// of 5 runs - Sep 2005).
//
// The following code actually changes the niceness of kernel-thread/LWP. It
// has an assumption that setpriority() only modifies one kernel-thread/LWP,
// not the entire user process, and user level threads are 1:1 mapped to kernel
// threads. It has always been the case, but could change in the future. For
// this reason, the code should not be used as default (ThreadPriorityPolicy=0).
// It is only used when ThreadPriorityPolicy=1 and requires root privilege.

...

第2982行:

 static int prio_init() {
   if (ThreadPriorityPolicy == 1) {
     // Only root can raise thread priority. Don't allow ThreadPriorityPolicy=1
     // if effective uid is not root. Perhaps, a more elegant way of doing
     // this is to test CAP_SYS_NICE capability, but that will require libcap.so
     if (geteuid() != 0) {
       if (!FLAG_IS_DEFAULT(ThreadPriorityPolicy)) {
         warning("-XX:ThreadPriorityPolicy requires root privilege on Linux");
       }
       ThreadPriorityPolicy = 0;
     }
   }
   return 0;
 }

...

第2997行:

OSReturn os::set_native_priority(Thread* thread, int newpri) {
  if ( !UseThreadPriorities || ThreadPriorityPolicy == 0 ) return OS_OK;

  int ret = setpriority(PRIO_PROCESS, thread->osthread()->thread_id(), newpri);
  return (ret == 0) ? OS_OK : OS_ERR;
}

原来如此!至少在Sun Java上,在Linux上,除非你已经完成了-XX:ThreadPriorityPolicy并且似​​乎需要root,否则你不会看到线程优先级。

答案 1 :(得分:1)

默认的Linux线程调度程序策略SCHED_OTHER不支持优先级。或者更准确地说,它支持具有一个值的优先级设置:0。另一个所谓的“实时”策略SCHED_FIFO和SCHED_RR支持更高的优先级,但仅适用于具有超级用户权限的进程。

答案 2 :(得分:0)

这里只是一个黑暗的镜头,但是在JVM中没有优先级的线程需要能够调整操作系统线程的优先级吗?

Linux(以及任何类Unix操作系统)限制了为root提供进程优先级的能力。我认为线程会有类似的限制。