preface

The Java thread scheduling mechanism is implemented by the JVM. If you have several threads and you want some threads to have longer execution time, or some threads to be allocated less execution time, this involves “thread priority”.

Priority level

Java divides thread priorities into 10 levels, and threads are created with default priorities if they are not explicitly declared. The JVM assigns probabilities of execution time based on the priority of each thread. The three constants are thread. MIN_PRIORITY, thread. NORM_PRIORITY, and thread. MAX_PRIORITY, which represent the minimum priority (1), default priority (5), and maximum priority (10) respectively.

Since the JVM implementation is based on the host operating system, there must be some mapping between Java priority values and the native thread priorities of various operating systems that encapsulates the priorities of all operating systems to provide uniform priority semantics. For example, a 1-10 priority value might map to a -20-19 priority value on Linux, whereas a Windows system has nine priorities to map.

A high priority is executed first?

Can we use the size of the priority value to control the order in which threads are executed? The answer is clearly no. This is because there are many factors that affect thread priority, including:

  • Different versions of the operating system and JVM can behave differently.
  • Priorities may mean different things to different operating system schedulers.
  • Some operating system schedulers do not support priorities.
  • For operating systems, the priority of threads can be “global” or “local”, and generally the priorities of different processes are independent of each other.
  • As mentioned earlier, different operating systems define different values for priorities, whereas Java only defines 1-10.
  • Operating systems often give increased priority to threads that have not been running for a long time.
  • The operating system’s thread scheduler may have a temporary priority adjustment policy when threads occur and so on.

A case in point

As a simple example, two threads may have different results each time they run.

public class ThreadPriorityTest {

	public static void main(String[] args) {
		Thread t = new MyThread();
		t.setPriority(10);
		t.setName("00");
		Thread t2 = new MyThread();
		t2.setPriority(8);
		t2.setName("11");
		t2.start();
		t.start();
	}

	static class MyThread extends Thread {
		public void run() {
			for(int i = 0; i < 5; i++) System.out.println(this.getName()); }}}Copy the code
11 00 00 00 00 11 11 11 11Copy the code

SetPriority method

This method is used to set the priority as follows:

  • Check whether you have permission to access the thread.
  • To check the validity of the priority value, theMIN_PRIORITYandMAX_PRIORITYIn between.
  • The maximum priority value of a thread group cannot be exceeded.
  • callsetPriority0Local method.
public static final int MIN_PRIORITY = 1;
public static final int NORM_PRIORITY = 5;
public static final int MAX_PRIORITY = 10;

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);
Copy the code

Local implementation

In Thread.c, setPriority0 is a method registered with the JVM that is bound to the JVM_SetThreadPriority function. So the implementation logic is in the JVM_SetThreadPriority function. Logic is:

  • JVMWrapper("JVM_SetThreadPriority")Used for debugging.
  • Obtain the mutex through MutexLocker.
  • Into an OOP object used by the JVM layer, which is the JVM’s description of the Java layer Thread object.
  • Sets the priority attribute value of an OOP object, which is passed herejava_lang_Thread::set_priorityTo set, i.ejava_thread->int_field_put(_priority_offset, priority)By calculating the offset address stored by the Priority attribute in the OOP object and then setting the value to that address.
  • throughjava_lang_Thread::threadGets the JavaThread pointer, that is(JavaThread*)java_thread->address_field(_eetop_offset), where the attributes of Thread belonging to the Java layer are obtained by calculating the EETOP offset. The reason for this is that JavaThread objects maintain a pointer to OOP, and OOP also maintains a pointer to JavaThread objects.
  • The last callThread::set_priorityTo set the thread priority at the operating system level by callingos::set_priorityTo implement.
static JNINativeMethod methods[] = {
    ...
    {"setPriority0"."(I)V",       (void *)&JVM_SetThreadPriority},
    ...
};

JVM_ENTRY(void, JVM_SetThreadPriority(JNIEnv* env, jobject jthread, jint prio))
  JVMWrapper("JVM_SetThreadPriority");
  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::set_priority(thr, (ThreadPriority)prio); } JVM_ENDCopy the code
void Thread::set_priority(Thread* thread, ThreadPriority priority) {
  debug_only(check_for_dangling_thread_pointer(thread);)
  (void)os::set_priority(thread, priority);
}
Copy the code

OS ::set_priority

  • First, determine the validity of the priority value.
  • The second is throughjava_to_os_priorityMap the priorities of the Java layer to the priorities of the operating system, which varies from operating system to operating system, as described below in priority Mapping.
  • Finally, callset_native_priorityThe thread priority function sets the thread priority. This varies from operating system to operating system, as described below in “OS Thread Priority Settings”.
OSReturn os::set_priority(Thread* thread, ThreadPriority p) {
  if (p >= MinPriority && p <= MaxPriority) {
    int priority = java_to_os_priority[p];
    return set_native_priority(thread, priority);
  } else {
    assert(false."Should not happen");
    returnOS_ERR; }}Copy the code

Priority mapping

The Java layer priority value needs to be converted to the operating system priority value. There is a mapping operation in this process. The javA_TO_OS_PRIORITY conversion is an array of 12 elements. Here are the values for Linux and Windows:

For Linux

Java 1,10 correspond to Linux 4 and -5, respectively. Linux threads have priorities ranging from -20 to 19, with -20 having the highest priority and 19 having the lowest priority. Java uses -5 to 4 to map priorities from 1 to 10.

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

For Windows

Both 1 and 2 of the Java layer map to THREAD_PRIORITY_LOWEST, and similarly, two consecutive values map to the same value.

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
};
Copy the code

The Windows platform has the following values, and you can see that all values are not mapped.

THREAD_MODE_BACKGROUND_BEGIN
THREAD_MODE_BACKGROUND_END
THREAD_PRIORITY_ABOVE_NORMAL
THREAD_PRIORITY_BELOW_NORMAL
THREAD_PRIORITY_HIGHEST
THREAD_PRIORITY_IDLE
THREAD_PRIORITY_LOWEST
THREAD_PRIORITY_NORMAL
THREAD_PRIORITY_TIME_CRITICAL
Copy the code

OS thread priority setting

The JVM calls the set_native_priority function to set the thread priority of the operating system. This function does different things for different operating systems. Let’s look at Linux and Windows.

For Linux

Call system function setPriority to achieve this, return OS_OK on success.

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;
}
Copy the code

For Windows

Call SetThreadPriority, return OS_OK on success.

OSReturn os::set_native_priority(Thread* thread, int priority) {
  if(! UseThreadPriorities)returnOS_OK; bool ret = SetThreadPriority(thread->osthread()->thread_handle(), priority) ! = 0;return ret ? OS_OK : OS_ERR;
}
Copy the code

————- Recommended reading ————

My 2017 article summary – Machine learning

My 2017 article summary – Java and Middleware

My 2017 article summary – Deep learning

My 2017 article summary — JDK source code article

My 2017 article summary – Natural Language Processing

My 2017 Article Round-up — Java Concurrent Article


Talk to me, ask me questions:

The public menu has been divided into “reading summary”, “distributed”, “machine learning”, “deep learning”, “NLP”, “Java depth”, “Java concurrent core”, “JDK source”, “Tomcat kernel” and so on, there may be a suitable for your appetite.

Why to write “Analysis of Tomcat Kernel Design”

Welcome to: