Java Multithreading series part 6.

In this article we will look at the priorities of Java threads.

Java thread priority

In the Thread class, the following attributes are used to represent priorities.

private int priority;
Copy the code

We can set the newPriority by setPriority(int newPriority) and get the priority of the thread by getPriority().

Some sources point to the following example: Java threads have a default priority of 5.

public static void main(String[] args) {
    Thread thread = new Thread();
    System.out.println(thread.getPriority());
}

// Print the result: 5
Copy the code

If we change the priority of the current thread to 4, we find that the priority of the child thread is also 4.

public static void main(String[] args) {
    Thread.currentThread().setPriority(4);
    Thread thread = new Thread();
    System.out.println(thread.getPriority());
}

// Print the result: 4
Copy the code

The default priority for a thread is 5. For a new thread, it should be 5, but it should be 4. Let’s look at the source code for Thread initializing Priority.

Thread parent = currentThread();
this.priority = parent.getPriority();
Copy the code

The default priority of a thread is to inherit the parent thread’s priority. In the example above, we set the parent thread’s priority to 4, causing the child thread’s priority to become 4 as well.

To be more precise, the default priority of the child thread is the same as that of the parent thread, and the default priority of the Main Java thread is 5.

Java defines three priorities, namely lowest priority (1), normal priority (5), and highest priority (10). The code is shown below. The Java priority range is [1, 10]. Setting the priority of any other number will throw 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;
Copy the code

Next, the role of thread priority. Let’s look at the following code. The code logic creates 3000 threads: 1000 priority 1 threads, 1000 priority 5 threads, and 1000 priority 10 threads. MinTimes is used to record the sum of 1000 MIN_PRIORITY thread runtime timestamps, normTimes is used to record 1000 NORM_PRIORITY thread runtime timestamps, MaxTimes is used to record the sum of 1000 MAX_PRIORITY thread runtime timestamps. By counting the sum of time stamps for each priority run, a smaller value indicates a higher priority. Let’s run it.

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 statistics:" + maxTimes.get());
        System.out.println("NormPriority statistics:" + normTimes.get());
        System.out.println("MinPriority statistics:" + minTimes.get());
        System.out.println("Difference between ordinary priority and highest priority:" + (normTimes.get() - maxTimes.get()) + "ms");
        System.out.println("Time difference between lowest priority and normal priority:" + (minTimes.get() - normTimes.get()) + "ms");

    }

    static class MyThread extends Thread {

        public MyThread(String name) {
            super(name);
        }

        @Override
        public void run(a) {
            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; }}}}Copy the code

The result is as follows:

# Part 1
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

# Part 2MaxPriority statistics: 1568986695523243 normPriority statistics: 1568986695526080 minPriority Statistics: 1568986695545414 Difference between the common priority and the highest priority: 2837ms difference between the lowest priority and common priority: 19334msCopy the code

Let’s analyze the results. A thread with a higher priority does not necessarily have a higher priority than a thread with a lower priority. Or to put it another way: code execution order is independent of thread priority. Looking at the results of the second part, we can see that the sum of the execution timestamps of the 1000 threads with the highest priority is the smallest, and the sum of the execution timestamps of the 1000 threads with the lowest priority is the largest, so we can know: A batch of high-priority threads will execute before a batch of low-priority threads, that is, high-priority threads are more likely to obtain CPU resources before low-priority threads.

Are there really 10 thread levels in each operating system?

Java, as a cross-platform language, has 10 levels of threads, but the priority values of threads mapped to different operating systems are different. The following tutorial will show you how to look up thread priority mapping values in the OpenJDK source code.

  1. seeThreadSource code, set thread priority eventually called the local methodsetPriority0();
private native void setPriority0(int newPriority);
Copy the code
  1. And then we hadOpenJDKThread.cFound in the codesetPriority0()Corresponding methodJVM_SetThreadPriority;
static JNINativeMethod methods[] = {
    ...
    {"setPriority0"."(I)V",       (void *)&JVM_SetThreadPriority},
    ...
};
Copy the code
  1. We according to theJVM_SetThreadPriorityfindjvm.cppThe corresponding code segment;
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
Copy the code
  1. Based on the code in step 3, we can see that the key isjava_lang_Thread::set_Priority()This code, keep lookingthread.cppIn the codeset_Priority()Methods;
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);
}
Copy the code
  1. Find that the code above ends up callingos::set_priority()“And continue to find outos.cppset_priority()Methods;
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) { int priority = java_to_os_priority[p]; return set_native_priority(thread, priority); } else { assert(false, "Should not happen"); return OS_ERR; }}Copy the code
  1. Finally found the priority code that eventually translates to each operating systemjava_to_os_priority[p]The next step is to find the values of the array for each operating system. For example, here isLinuxPriority of the system.
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
};
Copy the code

Well, you should know how to find the Java thread priority [1,10] that corresponds to the priority value in each operating system. Let me give you some statistics.

Java thread priority 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

For Windows, only the above constants can be found in the OpenJDK source code. The values can be found in the interface documentation provided by Microsoft. The link is here: setThreadPriority

We can also see some problems in this table. Even if we set a higher priority in Java code, the threads mapped to the operating system are not necessarily higher than those with a lower priority. They are probably the same priority. Looking at the extreme example of the Solaris operating system, priorities 5 to 10 map to the same thread level.

Think back to the example above why 3000 threads with MAX_PRIORITY 1000 threads will execute first? This works because our three priorities map to three different levels of Windows operating system threads. Let’s say I change 1, 5, 10 to 5, 6, 7, and the result is different.

Finally, remember: don’t treat thread priority like a silver bullet. A thread with a higher priority doesn’t have to execute before a thread with a lower priority.

This thread priority article also ended paragraph, friends after reading feel useful trouble to help a point in the look, recommend to friends around to see, the original is not easy.

Recommended reading

Understand the Java thread priority, but also the corresponding operating system priority, otherwise you will step on the pit

The most basic knowledge of threads

The boss told you to stop blocking

You can eat fast food and learn serial, parallel, and concurrency

Make a cup of tea and learn asynchrony

How much do we know about the process?

Design patterns seen and forgotten, forgotten and read?

If you reply “Design Mode”, you can get the ebook “One Story one Design Mode”

Think the article is useful to help forward & praise, thank you friends!