Java 執行緒優先權
Thread 類別中,使用下列屬性來代表優先權。
private int priority;
我們可以透過 setPriority(int newPriority) 來設定新的優先權,透過 getPriority() 來取得執行緒的優先權。
有些資料透過下面的範例就得出了一個結論:Java 執行緒預設優先權是 5。
public static void main(String[] args) { Thread thread = new Thread(); System.out.println(thread.getPriority()); } // 打印结果:5
其實這是大錯特錯的,只是看到了表面,看看下面的例子,我們把當前執行緒的優先權改為 4,發現子執行緒 thread 的優先權也是 4。
public static void main(String[] args) { Thread.currentThread().setPriority(4); Thread thread = new Thread(); System.out.println(thread.getPriority()); } // 打印结果:4
這啪啪啪打臉了,如果是線程預設優先級是 5,我們新創建的 thread 線程,沒設定優先級,理應是 5,但實際是 4。我們來看看 Thread 初始化 priority 的原始碼。
Thread parent = currentThread(); this.priority = parent.getPriority();
原來,執行緒預設的優先權是繼承父執行緒的優先權,上面例子我們把父執行緒的優先權設為 4,所以導致子執行緒的優先權也變成 4。
嚴謹一點說,子執行緒預設優先權和父執行緒一樣,Java 主執行緒預設的優先權是 5。
Java 中定義了 3 種優先級,分別是最低優先級(1)、正常優先級(5)、最高優先級(10),程式碼如下所示。 Java 優先權範圍是 [1, 10],設定其他數字的優先權都會拋出 IllegalArgumentException 例外。
/** * The minimum priority that a thread can have. */ public final static int MIN_PRIORITY = 1; /** * The default priority that is assigned to a thread. */ public final static int NORM_PRIORITY = 5; /** * The maximum priority that a thread can have. */ public final static int MAX_PRIORITY = 10;
接下來說說執行緒優先權的作用。先看下面程式碼,程式碼邏輯是創建了 3000 個線程,分別是: 1000 個優先權為 1 的線程, 1000 個優先權為 5 的線程,1000 個優先權為 10 的線程。用 minTimes 來記錄 1000 個 MIN_PRIORITY 線程運行時時間戳之和,用 normTimes 來記錄 1000 個 NORM_PRIORITY 線程運行時時間戳之和,用 maxTimes 來記錄 1000 個 MAX_PRIORITY 線程運行時時間戳和線程運行時。透過統計每個優先權的運行的時間戳總和,值越小代表的就是越優先執行。我們運行看看。
public class TestPriority { static AtomicLong minTimes = new AtomicLong(0); static AtomicLong normTimes = new AtomicLong(0); static AtomicLong maxTimes = new AtomicLong(0); public static void main(String[] args) { List<MyThread> minThreadList = new ArrayList<>(); List<MyThread> normThreadList = new ArrayList<>(); List<MyThread> maxThreadList = new ArrayList<>(); int count = 1000; for (int i = 0; i < count; i++) { MyThread myThread = new MyThread("min----" + i); myThread.setPriority(Thread.MIN_PRIORITY); minThreadList.add(myThread); } for (int i = 0; i < count; i++) { MyThread myThread = new MyThread("norm---" + i); myThread.setPriority(Thread.NORM_PRIORITY); normThreadList.add(myThread); } for (int i = 0; i < count; i++) { MyThread myThread = new MyThread("max----" + i); myThread.setPriority(Thread.MAX_PRIORITY); maxThreadList.add(myThread); } for (int i = 0; i < count; i++) { maxThreadList.get(i).start(); normThreadList.get(i).start(); minThreadList.get(i).start(); } try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("maxPriority 统计:" + maxTimes.get()); System.out.println("normPriority 统计:" + normTimes.get()); System.out.println("minPriority 统计:" + minTimes.get()); System.out.println("普通优先级与最高优先级相差时间:" + (normTimes.get() - maxTimes.get()) + "ms"); System.out.println("最低优先级与普通优先级相差时间:" + (minTimes.get() - normTimes.get()) + "ms"); } static class MyThread extends Thread { public MyThread(String name) { super(name); } @Override public void run() { System.out.println(this.getName() + " priority: " + this.getPriority()); switch (this.getPriority()) { case Thread.MAX_PRIORITY : maxTimes.getAndAdd(System.currentTimeMillis()); break; case Thread.NORM_PRIORITY : normTimes.getAndAdd(System.currentTimeMillis()); break; case Thread.MIN_PRIORITY : minTimes.getAndAdd(System.currentTimeMillis()); break; default: break; } } } }
執行結果如下:
# 第一部分 max----0 priority: 10 norm---0 priority: 5 max----1 priority: 10 max----2 priority: 10 norm---2 priority: 5 min----4 priority: 1 ....... max----899 priority: 10 min----912 priority: 1 min----847 priority: 5 min----883 priority: 1 # 第二部分 maxPriority 统计:1568986695523243 normPriority 统计:1568986695526080 minPriority 统计:1568986695545414 普通优先级与最高优先级相差时间:2837ms 最低优先级与普通优先级相差时间:19334ms
我們一起來分析一下結果。先看看第一部分,最開始執行的線程高優先級、普通優先級、低優先級都有,最後執行的線程也都有各個優先級的,這說明了:優先級高的線程不代表一定比優先權低的執行緒優先執行。也可以換另一種說法:程式碼執行順序跟執行緒的優先權無關。看看第二部分的結果,我們可以發現最高優先權的1000 個執行緒執行時間戳和最小,而最低優先權的1000 個執行緒執行時間戳之和最大,因此可以得知:一批高優先權的執行緒會比一批低優先權的執行緒優先執行,即高優先權的執行緒大機率比低優先的執行緒優先獲得CPU 資源。
各作業系統中真有 10 個執行緒等級麼?
Java 作為跨平台語言,執行緒有 10 個等級,但是映射到不同作業系統的執行緒優先權值不一樣。接下來教大家怎麼在 OpenJDK 原始碼中查各個作業系統中執行緒優先權映射的值。
看到Thread 原始碼,設定執行緒優先權最終呼叫了本機方法setPriority0();
private native void setPriority0(int newPriority);
接著我們在 OpenJDK 的 Thread.c 程式碼中找到 setPriority0() 對應的方法 Thread.c 程式碼中找到 setPriority0() 對應的方法 JVM_SetThreadPriority ;
static JNINativeMethod methods[] = { ... {"setPriority0", "(I)V", (void *)&JVM_SetThreadPriority}, ...};
我們根據 JVM_SetThreadPriority 找到 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 MutexLocker ml(Threads_lock); 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
根據第3 步驟中的程式碼,我們可以發現關鍵是 java_lang_Thread::set_Priority() 這段程式碼,繼續找 thread.cpp 程式碼中的 set_Priority() 方法;
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); }
以上是Java執行緒優先權的詳細內容。更多資訊請關注PHP中文網其他相關文章!