从JVM源码角度解析设置了线程优先级为什么还不一定优先执行

理论上是优先级越高的线程会优先被CPU调度的机会,但是事实上往往并不是这样的,设置线程优先级同样也是一个hint操作,对于root用户,它会hint操作系统你想要设置的优先级别,否则它会被忽略。 如果CPU 比较忙,设置优先级可能会获得更多的CPU时间片,但是闲时优先级的高低几乎不会有任何作用。所有,在程序设计中不要企图使用线程优先级绑定某些特定的业务,或者让业务严重依赖于线程优先级。

现在我们来看下线程优先级的源码,setPriority(…)的源码如下:

  public final static int MAX_PRIORITY = 10;
  public static final int NORM_PRIORITY = 5;
  public final static int MIN_PRIORITY = 1;
  public final void setPriority(int newPriority) {
       ThreadGroup g;
       checkAccess();
       if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
           throw new IllegalArgumentException();
       }
       if((g = getThreadGroup()) != null) {
           if (newPriority > g.getMaxPriority()) {
               newPriority = g.getMaxPriority();
           }
           setPriority0(priority = newPriority);
       }
   }

private native void setPriority0(int newPriority);

从源码中可知,线程默认的级别是5,如果设定的线程级别大于10或者小于1就会抛出IllegalArgumentException异常,如果指定的线程优先级大于线程所在的group的优先级,那么指定的优先级将会失效,取而代之的是group的最大优先级,否则就调用native方法setPriority0(…)进行优先级设置,

在Thread.c 中可以找到setPriority0的方法映射,文件路径为jdk\src\share\native\java\lang\Thread.c :
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OkvlR3T6-1665286490312)(https://note.youdao.com/yws/res/35606/WEBRESOURCE3799b5017bd8e900be31a5009a781565)]

从上图可知, setPriority0()方法对应的实现源码是 JVM_SetThreadPriority,文件路径为hotspot\src\share\vm\prims\jvm.cpp,实现源码如下:

JVM_ENTRY(void, JVM_SetThreadPriority(JNIEnv* env, jobject jthread, jint prio))
  JVMWrapper("JVM_SetThreadPriority");
  // Ensure that the C++ Thread and OSThread structures aren't freed before we operate
  //确保在我们操作之前C++ Thread和OSThread 没有被释放
  MutexLocker ml(Threads_lock);
 //把非null的java堆内存地址jthread转换为C++指针
  oop java_thread = JNIHandles::resolve_non_null(jthread);
  java_lang_Thread::set_priority(java_thread, (ThreadPriority)prio);
  JavaThread* thr = java_lang_Thread::thread(java_thread);
  if (thr != NULL) {                  // Thread not yet started; priority pushed down when it is
    Thread::set_priority(thr, (ThreadPriority)prio);
  }
JVM_END

在代码中,我们重点看 java_lang_Thread::set_priority(java_thread, (ThreadPriority)prio); 接着来查看set_priority方法的实现,文件路径为Hotspot\src\share\vm\runtime\thread.cpp,其源码如下:

void Thread::set_priority(Thread* thread, ThreadPriority priority) {
  trace("set priority", thread);
  debug_only(check_for_dangling_thread_pointer(thread);)
  // Can return an error!
  (void)os::set_priority(thread, priority);
}

从源码可知,最终调用的是操作系统的os::set_priority(…)方法。接着查看 (void)os::set_priority源码, 文件路径为Hotspot\src\share\vm\runtime\os.cpp,其源码如下:


OSReturn os::set_priority(Thread* thread, ThreadPriority p) {
#ifdef ASSERT
  if (!(!thread->is_Java_thread() ||
         Thread::current() == thread  ||
         Threads_lock->owned_by_self()
         || thread->is_Compiler_thread()
        )) {
    assert(false, "possibility of dangling Thread pointer");
  }
#endif

  if (p >= MinPriority && p <= MaxPriority) {
  //核心代码,不同jvm平台优先级不一样
    int priority = java_to_os_priority[p];
    return set_native_priority(thread, priority);
  } else {
    assert(false, "Should not happen");
    return OS_ERR;
  }
}

从源码中可知,不同的jvm操作平台,优先级代码也不一样,在这里调用java_to_os_priority根据平台不同转换成不同的优先级,最后调用set_native_priority(…)方法进行线程的优先级设置。

我们来看看常用的liunx和windows下的线程优先级值, liunx的优先级值如下:

int os::java_to_os_priority[CriticalPriority + 1] = {
  19,              // 0 Entry should never be used

   4,              // 1 MinPriority
   3,              // 2
   2,              // 3

   1,              // 4
   0,              // 5 NormPriority
  -1,              // 6

  -2,              // 7
  -3,              // 8
  -4,              // 9 NearMaxPriority

  -5,              // 10 MaxPriority

  -5               // 11 CriticalPriority
};

windows的优先级值如下:

int os::java_to_os_priority[CriticalPriority + 1] = {
  THREAD_PRIORITY_IDLE,                         // 0  Entry should never be used
  THREAD_PRIORITY_LOWEST,                       // 1  MinPriority
  THREAD_PRIORITY_LOWEST,                       // 2
  THREAD_PRIORITY_BELOW_NORMAL,                 // 3
  THREAD_PRIORITY_BELOW_NORMAL,                 // 4
  THREAD_PRIORITY_NORMAL,                       // 5  NormPriority
  THREAD_PRIORITY_NORMAL,                       // 6
  THREAD_PRIORITY_ABOVE_NORMAL,                 // 7
  THREAD_PRIORITY_ABOVE_NORMAL,                 // 8
  THREAD_PRIORITY_HIGHEST,                      // 9  NearMaxPriority
  THREAD_PRIORITY_HIGHEST,                      // 10 MaxPriority
  THREAD_PRIORITY_HIGHEST                       // 11 CriticalPriority
};

自此总结一下java线程优先级1-10 对应各个操作系统中的优先级:

Java 线程优先级LinuxWindowsAppleBsdSolaris
14THREAD_PRIORITY_LOWEST(-2)2700
23THREAD_PRIORITY_LOWEST(-2)28332
32THREAD_PRIORITY_BELOW_NORMAL(-1)29664
41THREAD_PRIORITY_BELOW_NORMAL(-1)301096
50THREAD_PRIORITY_NORMAL(0)3115127
6-1THREAD_PRIORITY_NORMAL(0)3218127
7-2THREAD_PRIORITY_ABOVE_NORMAL(1)3321127
8-3THREAD_PRIORITY_ABOVE_NORMAL(1)3425127
9-4THREAD_PRIORITY_HIGHEST(2)3528127
10-5THREAD_PRIORITY_HIGHEST(2)3631127

从源代码可知道为什么我们在java代码中设置了比较高的线程优先级,但是不一定先执行的原因了, 因为java线程优先级对应的不同JVM操作系统的线程并不定是高的,有可能是低优先级也有可能是相同等级的优先级。

总结:优先级高的线程不代表一定比优先级低的线程优先执行。一批高优先级的线程会比一批低优先级的线程优先执行,即高优先级的线程大概率比低优先的线程优先获得 CPU 资源。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

弯_弯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值