preface

Sleep is used to put the Thread to sleep. Let’s see what happens in the JVM when this statement is executed.

A simple example

Here is a simple example of putting the main thread to sleep for 5 seconds.

public class TestSleep { public static void main(String[] args) { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); }}}Copy the code

Threads in the JVM

Before moving on to the JVM layer to look at the start0 native method, let’s take a look at the relevant threads in the JVM, which will help us understand the mapping between Java layer threads and threads in the JVM.

In the JVM, Thread classes are also defined in C++, and their inheritance structure is as follows. The main java.lang.Thread, JavaThread, and OSThread are related to the Java layer Thread to the JVM layer.

  • Java.lang.Thread is a Thread object belonging to the Java layer. Each Java layer object is represented in the JVM using OOP, so it also generates an OOP in the JVM.
  • Thread is a Thread base class defined by C++. As a base class for all threads except OSThread, it contains Pointers to OSThread objects.
  • JavaThread is a thread class defined by C++. Thread objects we create in the Java layer are represented by JavaThread objects, which contain oop Pointers to threads.
  • Osthreads are threads defined by C++. They do not inherit from other threads. Osthreads are the JVM’s unified abstraction for threads of different operating systems.
--Thread
	--JavaThread
		--CodeCacheSweeperThread
		--CompilerThread
		--JvmtiAgentThread
		--ServiceThread
	--NamedThread
		--ConcurrentGCThread
		--VMThread
		--WorkerThread
			--AbstractGangWorker
			--GCTaskThread
	--WatcherThread
--OSThread
Copy the code

Sleep method

In the Thread class, sleep is a static and local method.

public static native void sleep(long millis) throws InterruptedException;
Copy the code

Thread.c

In Thread.c, sleep is a method registered in the JVM and is bound to the JVM_Sleep function in the JVM, so the implementation logic is in the JVM_Sleep function. Logic is:

  • JVMWrapper("JVM_Sleep")Used for debugging.
  • The sleep time cannot be negative.
  • Whether it has been interrupted.
  • JavaThreadSleepState jtss(thread)It is used to modify the thread state and do some statistics, and when sleep is over, it is modified back to the thread state in the destructor of JavaThreadSleepState.
  • If the sleep time is 0, then according toConvertSleepToYieldDo something different, and it says whether or not to yield the sleep operation. Respectively calledos::naked_yieldandos::sleepProcessing, encapsulating the call implementation of different operating systems, followed by Windows as an example to see the corresponding implementation.
  • throughthread->osthread()->get_state()Gets the OSThread object and sets its state toSLEEPINGWait until the sleep ends and set it back to the original state.
  • If the sleep time is greater than 0, it does something similar, but interrupts are supported.
  • Sending an event ends.
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
Copy the code

os::naked_yield

The naked_yield function is implemented simply by calling the SwitchToThread system function directly. This function allows the system to see if another thread urgently needs the CPU, relinquish the CPU to another thread, and return immediately if there are no other threads.

void os::naked_yield() {
  SwitchToThread();
}
Copy the code

os::sleep

  • Gets the maximum size limit.
  • If the limit is exceeded, it is subtracted into multiple recursive callssleepFunction.
  • The OSThread object is obtained, and the thread state is set to wait via OSThreadWaitState. The modifications are performed in the constructor and destructor, respectively.
  • Depending on whether to support interrupt to do different implementation, do not need interrupt directly callSleepSystem function to achieve.
  • If you want to support interrupts, do the following.
  • ThreadBlockInVM checks whether the current thread is needed to enter SafePoint, but more on that later.
  • And then mainly toWaitForMultipleObjectsSystem function that can wait the number of milliseconds specified by the specified object. If the object does not receive any signal while waiting, it returns after the specified number of millisecondsWAIT_TIMEOUT, if the object receives a signal during the waiting process, the waiting will be terminated in advance, and the returned value isOS_INTRPT, that is, it is interrupted.
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;
}
Copy the code

ThreadBlockInVM

ThreadBlockInVM checks whether the current thread is entering SafePoint. Its main logic is as follows:

  • First set the Java thread state, increment the state by one, from_thread_in_vm = 6into_thread_in_vm_trans = 7, from “Run the VM’s own code” to “corresponding transition state”.
  • os::is_MP()It is used to determine whether a computer system is multi-core or not. In the case of multi-core, memory barrier processing is required, so that each thread can synchronize state in real time.
  • Memory barriers come in two ways, one isrderAccess::fence(), its implementation is directly through the CPU instructions to achieve, assembly instructions for__asm__ volatile ("lock; Addl $0,0(%% RSP)" : : : "cc", "memory");This way is relatively costly. And the other isInterfaceSupport::serialize_memory, by JVM simulation implementation, higher efficiency.
  • callSafepointSynchronize::blockTry to block at this safe point.
  • Set the Java thread state to_thread_blocked, that is, blocking.
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 inparticular 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();)
  }
Copy the code

————- Recommended reading ————

Summary of my open Source projects (Machine & Deep Learning, NLP, Network IO, AIML, mysql protocol, Chatbot)

Why to write “Analysis of Tomcat Kernel Design”

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:

Welcome to: