理论上是优先级越高的线程会优先被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 线程优先级 | Linux | Windows | Apple | Bsd | Solaris |
---|---|---|---|---|---|
1 | 4 | THREAD_PRIORITY_LOWEST(-2) | 27 | 0 | 0 |
2 | 3 | THREAD_PRIORITY_LOWEST(-2) | 28 | 3 | 32 |
3 | 2 | THREAD_PRIORITY_BELOW_NORMAL(-1) | 29 | 6 | 64 |
4 | 1 | THREAD_PRIORITY_BELOW_NORMAL(-1) | 30 | 10 | 96 |
5 | 0 | THREAD_PRIORITY_NORMAL(0) | 31 | 15 | 127 |
6 | -1 | THREAD_PRIORITY_NORMAL(0) | 32 | 18 | 127 |
7 | -2 | THREAD_PRIORITY_ABOVE_NORMAL(1) | 33 | 21 | 127 |
8 | -3 | THREAD_PRIORITY_ABOVE_NORMAL(1) | 34 | 25 | 127 |
9 | -4 | THREAD_PRIORITY_HIGHEST(2) | 35 | 28 | 127 |
10 | -5 | THREAD_PRIORITY_HIGHEST(2) | 36 | 31 | 127 |
从源代码可知道为什么我们在java代码中设置了比较高的线程优先级,但是不一定先执行的原因了, 因为java线程优先级对应的不同JVM操作系统的线程并不定是高的,有可能是低优先级也有可能是相同等级的优先级。
总结:优先级高的线程不代表一定比优先级低的线程优先执行。一批高优先级的线程会比一批低优先级的线程优先执行,即高优先级的线程大概率比低优先的线程优先获得 CPU 资源。