Приоритет потоков от Java к JVM к ОС

Java JVM Операционная система Windows
Приоритет потоков от Java к JVM к ОС

предисловие

Механизм планирования потоков Java реализуется JVM.Если есть несколько потоков, и вы хотите, чтобы некоторые потоки имели более длительное время выполнения или некоторые потоки выделяли меньше времени выполнения, тогда задействован «приоритет потока».

приоритет

Java делит приоритет потока на 10 уровней.При создании потока, если он явно не объявлен, используется приоритет по умолчанию.JVM будет распределять вероятность времени выполнения в соответствии с приоритетом каждого потока. Есть три константыThread.MIN_PRIORITY,Thread.NORM_PRIORITY,Thread.MAX_PRIORITYСоответственно представляют минимальное значение приоритета (1), значение приоритета по умолчанию (5) и максимальное значение приоритета (10).

Поскольку реализация JVM основана на операционной системе хоста, должно быть какое-то отношение отображения между значением приоритета Java и собственными приоритетами потоков различных операционных систем, которого достаточно, чтобы инкапсулировать приоритеты всех операционных систем, чтобы обеспечить унифицированная приоритетная семантика. Например, значение приоритета от 1 до 10 может быть сопоставлено со значением приоритета от -20 до 19 в Linux, в то время как в системе Windows будет 9 приоритетов для сопоставления.

Высокий приоритет для выполнения в первую очередь?

Можем ли мы использовать размер значения приоритета для управления порядком выполнения потоков? Очевидно, что нет. Это связано с тем, что существует множество факторов, влияющих на приоритет потока, в том числе:

  • Различные версии операционной системы и JVM могут вести себя по-разному.
  • Приоритет может иметь разные значения для разных планировщиков операционных систем.
  • Некоторые планировщики операционных систем не поддерживают приоритет.
  • Для операционной системы приоритет потоков делится на «глобальный» и «локальный», и вообще приоритеты разных процессов не зависят друг от друга.
  • Как упоминалось ранее, разные операционные системы имеют разные определения приоритета, а Java определяет только от 1 до 10.
  • Операционная система часто увеличивает приоритет потоков, которые не выполняются в течение длительного времени.
  • Планировщик потоков операционной системы может иметь определенную временную стратегию настройки приоритета при возникновении потоков и так далее.

один пример

Вот простой пример, результаты каждого запуска двух потоков могут не совпадать.

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());
		}
	}
}
11
00
00
00
00
00
11
11
11
11

метод setPriority

Этот метод используется для установки приоритета, логика такова:

  • Проверьте, есть ли у вас разрешение на доступ к потоку.
  • Проверьте действительность значения приоритета, должно быть вMIN_PRIORITYа такжеMAX_PRIORITYмежду.
  • Нельзя превышать максимальное значение приоритета группы потоков.
  • перечислитьsetPriority0Родной метод.
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);

локальная реализация

Собственные методы, объявленные на уровне Java, соответственно реализованы в Thread.c,setPriority0это метод, зарегистрированный в JVM, который совпадает с методом в JVMJVM_SetThreadPriorityФункция связана, поэтому логика реализации находится вJVM_SetThreadPriorityв функции. Логика такова:

  • JVMWrapper("JVM_SetThreadPriority")для отладки.
  • Получите мьютекс через MutexLocker.
  • Преобразуется в объект oop, используемый уровнем JVM, который является описанием объекта Thread уровня Java в JVM.
  • Установите значение атрибута приоритета объекта oop, здесьjava_lang_Thread::set_priorityустановить, т.е.java_thread->int_field_put(_priority_offset, priority), здесь путем вычисления адреса смещения, хранящегося в свойстве приоритета в объекте oop, а затем присваивании значения этому адресу.
  • пройти черезjava_lang_Thread::threadПолучите указатель JavaThread, т.е.(JavaThread*)java_thread->address_field(_eetop_offset), который получается путем вычисления смещения eetop, которое является атрибутом в классе Thread уровня Java. Причина, по которой это можно сделать, заключается в том, что объект JavaThread поддерживает указатель на oop, который также поддерживает указатель на объект JavaThread.
  • последний звонокThread::set_priorityЧтобы установить приоритет потока на уровне операционной системы, вызовитеos::set_priorityреализовать.
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_END
void Thread::set_priority(Thread* thread, ThreadPriority priority) {
  debug_only(check_for_dangling_thread_pointer(thread);)
  (void)os::set_priority(thread, priority);
}

см. далееos::set_priorityРеализация функции:

  • Во-первых, определите достоверность значения приоритета.
  • с последующимjava_to_os_priorityСопоставьте приоритет уровня Java с приоритетом операционной системы.Разные операционные системы различаются и подробно описаны в разделе «Сопоставление приоритетов» ниже.
  • наконец позвонюset_native_priorityФункция устанавливает приоритет потока, который различен для разных операционных систем, подробно описан в разделе "Настройка приоритета потока ОС" ниже.
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");
    return OS_ERR;
  }
}

сопоставление приоритетов

Значение приоритета слоя Java необходимо преобразовать в значение приоритета операционной системы.В середине есть операция сопоставления.Давайте посмотрим, как его сопоставить? упоминалось ранее черезjava_to_os_priorityConvert, это массив, всего в этом массиве 12 элементов. Посмотрим на значения для операционных систем Linux и Windows:

Для Linux

1 и 10 уровня Java соответствуют уровням 4 и -5 Linux соответственно. Диапазон значений приоритета потоков Linux составляет от -20 до 19, из которых -20 — самый высокий приоритет, а 19 — самый низкий приоритет. 4, чтобы сопоставить приоритеты от 1 до 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
};

Для Windows

И 1, и 2 слоя Java отображаются наTHREAD_PRIORITY_LOWEST, и другие аналогичны, два последовательных значения сопоставляются с одним и тем же значением соответственно.

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
};

Платформа Windows имеет следующие значения, вы можете видеть, что не все значения сопоставлены.

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

Настройка приоритета потока ОС

Как упоминалось ранее, JVM вызываетset_native_priorityФункция устанавливает приоритет потока операционной системы.Эта функция будет выполнять различную обработку в зависимости от разных операционных систем.Давайте посмотрим на ситуацию с Linux и Windows.

Для Linux

функция системы вызоваsetpriorityдля достижения и успешно возвращает OS_OK.

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;
}

Для Windows

функция системы вызоваSetThreadPriorityдля достижения и успешно возвращает OS_OK.

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

------------- Рекомендуем прочитать ------------

Резюме моей статьи за 2017 год — машинное обучение

Краткое изложение моих статей за 2017 год — Java и промежуточное ПО

Резюме моих статей 2017 года — глубокое обучение

Краткое изложение моих статей за 2017 год — исходный код JDK

Резюме моей статьи за 2017 год — обработка естественного языка

Резюме моих статей 2017 года — Java Concurrency


Поговори со мной, задай мне вопросы:

这里写图片描述

Меню официальной учетной записи было разделено на «Сводка для чтения», «Распределенное», «Машинное обучение», «Глубокое обучение», «НЛП», «Глубина Java», «Ядро параллелизма Java», «Исходный код JDK», "Tomcat Core" "Подождите, может быть, есть тот, который соответствует вашему аппетиту.

Зачем писать «Анализ проектирования ядра Tomcat»

Добро пожаловать, чтобы следовать:

这里写图片描述