предисловие
Иногда необходимо перевести поток в спящее состояние в Java, тогда мы обычно переходимThread.sleep
Переведите поток в спящий режим и посмотрите, что делает выполнение оператора в JVM.
Простой пример
Вот простой пример, который усыпляет основной поток на 5 секунд.
public class TestSleep {
public static void main(String[] args) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Потоки в JVM
Продолжайте смотреть на слой JVMstart0
Перед нативным методом давайте сначала разберемся с соответствующими потоками в JVM, что поможет лучше понять соответствие между потоками уровня Java и потоками в JVM.
В JVM некоторые классы Thread также определены в C++, структура их наследования следующая: для потока уровня Java к уровню JVM основными родственными являются java.lang.Thread, JavaThread и OSThread уровня Java.
- java.lang.Thread принадлежит объекту потока уровня Java.Каждый объект уровня Java будет представлен как oop в JVM, поэтому он также будет генерировать oop в JVM.
- Thread — это базовый класс потока, определенный в C++.За исключением класса OSThread, в качестве базового класса других потоков он содержит указатель на объект OSThread.
- JavaThread — это класс потока, определенный в C++.Объект потока, который мы создаем на уровне Java, будет представлен объектом JavaThread, который содержит указатель на цикл потока.
- OSThread – это поток, определенный в C++. Он не образует отношения наследования с другими потоками. Это унифицированная абстракция JVM для потоков различных операционных систем. Он поддерживает дескрипторы потоков операционной системы и используется для получения потоков операционной системы.
--Thread
--JavaThread
--CodeCacheSweeperThread
--CompilerThread
--JvmtiAgentThread
--ServiceThread
--NamedThread
--ConcurrentGCThread
--VMThread
--WorkerThread
--AbstractGangWorker
--GCTaskThread
--WatcherThread
--OSThread
метод сна
В классе Threadsleep
является статическим и собственным методом.
public static native void sleep(long millis) throws InterruptedException;
Thread.c
Собственные методы, объявленные на уровне Java, соответственно реализованы в Thread.c,sleep
это метод, зарегистрированный в JVM, который совпадает с методом в JVMJVM_Sleep
Функция связана, поэтому логика реализации находится вJVM_Sleep
в функции. Логика такова:
-
JVMWrapper("JVM_Sleep")
для отладки. - Время сна не может быть отрицательным.
- был прерван.
-
JavaThreadSleepState jtss(thread)
Он используется для изменения состояния потока и создания некоторой статистики.Когда спящий режим закончится, он будет изменен обратно в состояние потока и изменен в деструкторе JavaThreadSleepState. - Если время сна равно 0, согласно
ConvertSleepToYield
Выполните другую обработку, это указывает, следует ли превратить операцию сна в операцию выхода. звоните отдельноos::naked_yield
иos::sleep
Обработка инкапсулирует реализацию вызова различных операционных систем и берет Windows в качестве примера, чтобы увидеть соответствующую реализацию. - пройти через
thread->osthread()->get_state()
Получите объект OSThread и установите его состояние вSLEEPING
Вернитесь в исходное состояние после окончания сна. - Если время сна больше 0, сделайте то же самое, но с поддержкой прерываний.
- Отправить событие, конец.
JVM_ENTRY(void, JVM_Sleep(JNIEnv* env, jclass threadClass, jlong millis))
JVMWrapper("JVM_Sleep");
if (millis < 0) {
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
}
if (Thread::is_interrupted (THREAD, true) && !HAS_PENDING_EXCEPTION) {
THROW_MSG(vmSymbols::java_lang_InterruptedException(), "sleep interrupted");
}
JavaThreadSleepState jtss(thread);
HOTSPOT_THREAD_SLEEP_BEGIN(millis);
EventThreadSleep event;
if (millis == 0) {
if (ConvertSleepToYield) {
os::naked_yield();
} else {
ThreadState old_state = thread->osthread()->get_state();
thread->osthread()->set_state(SLEEPING);
os::sleep(thread, MinSleepInterval, false);
thread->osthread()->set_state(old_state);
}
} else {
ThreadState old_state = thread->osthread()->get_state();
thread->osthread()->set_state(SLEEPING);
if (os::sleep(thread, millis, true) == OS_INTRPT) {
if (!HAS_PENDING_EXCEPTION) {
if (event.should_commit()) {
event.set_time(millis);
event.commit();
}
HOTSPOT_THREAD_SLEEP_END(1);
THROW_MSG(vmSymbols::java_lang_InterruptedException(), "sleep interrupted");
}
}
thread->osthread()->set_state(old_state);
}
if (event.should_commit()) {
event.set_time(millis);
event.commit();
}
HOTSPOT_THREAD_SLEEP_END(0);
JVM_END
os::naked_yield
naked_yield
Реализация функции очень проста, достаточно вызвать ее напрямуюSwitchToThread
системная функция. Эта функция позволяет системе видеть, есть ли другие потоки, которым срочно нужен ЦП, отдавать ЦП другим потокам и немедленно возвращаться, если других потоков нет.
void os::naked_yield() {
SwitchToThread();
}
os::sleep
- Получите максимальный предельный размер лимита.
- Если он превышает лимит, он преобразуется в несколько рекурсивных вызовов путем вычитания
sleep
функция. - Получите объект OSThread, а затем установите состояние ожидания потока через OSThreadWaitState, а операции модификации реализуются в конструкторе и деструкторе соответственно.
- Различные реализации выполняются в зависимости от того, поддерживаются ли прерывания, и они вызываются напрямую без прерываний.
Sleep
системные функции для реализации. - Если вы хотите поддерживать прерывания, выполните следующую обработку.
- ThreadBlockInVM в основном проверяет, нужно ли текущему потоку войти в точку сохранения, и мы подробно рассмотрим это позже.
- Затем в основном к
WaitForMultipleObjects
Системная функция, ожидающая заданное количество миллисекунд для указанного объекта. Если объект не получает никакого сигнала в процессе ожидания, он вернется через указанное количество миллисекунд.WAIT_TIMEOUT
, если объект получает сигнал в процессе ожидания, ожидание отменяется заранее, а возвращаемое значение равноOS_INTRPT
, что означает, что он был прерван.
int os::sleep(Thread* thread, jlong ms, bool interruptable) {
jlong limit = (jlong) MAXDWORD;
while (ms > limit) {
int res;
if ((res = sleep(thread, limit, interruptable)) != OS_TIMEOUT) {
return res;
}
ms -= limit;
}
assert(thread == Thread::current(), "thread consistency check");
OSThread* osthread = thread->osthread();
OSThreadWaitState osts(osthread, false /* not Object.wait() */);
int result;
if (interruptable) {
assert(thread->is_Java_thread(), "must be java thread");
JavaThread *jt = (JavaThread *) thread;
ThreadBlockInVM tbivm(jt);
jt->set_suspend_equivalent();
HANDLE events[1];
events[0] = osthread->interrupt_event();
HighResolutionInterval *phri=NULL;
if (!ForceTimeHighResolution) {
phri = new HighResolutionInterval(ms);
}
if (WaitForMultipleObjects(1, events, FALSE, (DWORD)ms) == WAIT_TIMEOUT) {
result = OS_TIMEOUT;
} else {
ResetEvent(osthread->interrupt_event());
osthread->set_interrupted(false);
result = OS_INTRPT;
}
delete phri;
jt->check_and_wait_while_suspended();
} else {
assert(!thread->is_Java_thread(), "must not be java thread");
Sleep((long) ms);
result = OS_TIMEOUT;
}
return result;
}
ThreadBlockInVM
Как упоминалось ранее, ThreadBlockInVM будет проверять, нужно ли текущему потоку заходить в safepoint, его основная логика такова:
- Сначала установите состояние потока Java, увеличьте состояние на единицу, на
_thread_in_vm = 6
стать_thread_in_vm_trans = 7
, от «запуска собственного кода виртуальной машины» до «соответствующего переходного состояния». -
os::is_MP()
Он используется для определения того, является ли компьютерная система многоядерной системой.В случае многоядерности требуется обработка барьера памяти, чтобы позволить каждому потоку синхронизировать состояние в реальном времени. - Есть два способа барьера памяти, один из них
rderAccess::fence()
, его реализация непосредственно реализуется инструкциями ЦП, а инструкции по сборке__asm__ volatile ("lock; addl $0,0(%%rsp)" : : : "cc", "memory");
, этот способ дороже. И еще одинInterfaceSupport::serialize_memory
, реализованный с помощью моделирования JVM, что является более эффективным. - перечислить
SafepointSynchronize::block
Попытайтесь заблокировать эту точку безопасности. - Установите состояние потока Java в
_thread_blocked
, т.е. блокировка.
static inline void transition_and_fence(JavaThread *thread, JavaThreadState from, JavaThreadState to) {
assert(thread->thread_state() == from, "coming from wrong thread state");
assert((from & 1) == 0 && (to & 1) == 0, "odd numbers are transitions states");
thread->set_thread_state((JavaThreadState)(from + 1));
if (os::is_MP()) {
if (UseMembar) {
OrderAccess::fence();
} else {
// Must use this rather than serialization page in particular on Windows
InterfaceSupport::serialize_memory(thread);
}
}
if (SafepointSynchronize::do_call_back()) {
SafepointSynchronize::block(thread);
}
thread->set_thread_state(to);
CHECK_UNHANDLED_OOPS_ONLY(thread->clear_unhandled_oops();)
}
------------- Рекомендуем прочитать ------------
Зачем писать «Анализ проектирования ядра Tomcat»
Резюме моей статьи за 2017 год — машинное обучение
Краткое изложение моих статей за 2017 год — Java и промежуточное ПО
Резюме моих статей 2017 года — глубокое обучение
Краткое изложение моих статей за 2017 год — исходный код JDK
Резюме моей статьи за 2017 год — обработка естественного языка
Резюме моих статей 2017 года — Java Concurrency
Поговори со мной, задай мне вопросы:
Добро пожаловать, чтобы следовать: