The emergence of threads

  • Threads can be considered lightweight processes, so they can be created and destroyed faster than processes
  • In the multi-core CPU, the use of multi-threading can realize the true sense of parallel execution (single-core CPU threads are executed through the CPU time slice constantly switching, only one thread will be scheduled by the CPU at any time)
  • In an application process, multiple concurrent tasks exist. If one task is blocked, other tasks will also be blocked. By creating different threads for different tasks, the real-time performance of the program can be improved

Thread life cycle (6 states)

NEW, RUNNABLE, BLOCKED, WAITING, TIME_WAITING, TERMINATED

  • NEW: Initial state, thread, but the thread’s start method has not been called
  • JAVA refers to both the ready and RUNNABLE states of a thread in an operating system as “running.”
  • BLOCKED: a thread enters the wait state. The thread has given up its CPU usage for some reason
    • Wait blocking: The running thread executes the wait method (the wait method can only be executed if the lock is acquired), and the JVM places the current thread on the wait queue
    • Synchronous blocking: When a running thread acquirement a synchronous lock on an object, if the lock is occupied by another thread, the JVM adds the current thread to the lock pool
    • Other blocking: The running Thread executed thread. sleep or join, orAn I/O request was sent. ProcedureWhen the sleep ends, the JOIN thread terminates, and the I/O processing completes, the thread resumes
    • TIME_WAITING: Indicates the timeout waiting state. After a timeout, the system automatically returns
    • TERMINATED: indicates that the current thread is TERMINATED
/**
 * A thread state.  A thread can be in one of the following states:
 * <ul>
 * <li>{@link #NEW}<br>
 *     A thread that has not yet started is in this state.
 *     </li>
 * <li>{@link #RUNNABLE}<br>
 *     A thread executing in the Java virtual machine is in this state.
 *     </li>
 * <li>{@link #BLOCKED}<br>
 *     A thread that is blocked waiting for a monitor lock
 *     is in this state.
 *     </li>
 * <li>{@link #WAITING}<br>
 *     A thread that is waiting indefinitely for another thread to
 *     perform a particular action is in this state.
 *     </li>
 * <li>{@link #TIMED_WAITING}<br>
 *     A thread that is waiting for another thread to perform an action
 *     for up to a specified waiting time is in this state.
 *     </li>
 * <li>{@link #TERMINATED}<br>
 *     A thread that has exited is in this state.
 *     </li>
 * </ul>
 *
 * <p>
 * A thread can be in only one state at a given point in time.
 * These states are virtual machine states which do not reflect
 * any operating system thread states.
 *
 * @since   1.5
 * @see #getState
 */
public enum State {
  /** * Thread state for a thread which has not yet started. */
  NEW,

  /** * Thread state for a runnable thread. A thread in the runnable * state is executing in the Java virtual machine but it may * be waiting for other resources from the operating system * such as processor. */
  RUNNABLE,

  /**
   * Thread state for a thread blocked waiting for a monitor lock.
   * A thread in the blocked state is waiting for a monitor lock
   * to enter a synchronized block/method or
   * reenter a synchronized block/method after calling
   * {@link Object#wait() Object.wait}.
   */
  BLOCKED,

  /**
   * Thread state for a waiting thread.
   * A thread is in the waiting state due to calling one of the
   * following methods:
   * <ul>
   *   <li>{@link Object#wait() Object.wait} with no timeout</li>
   *   <li>{@link #join() Thread.join} with no timeout</li>
   *   <li>{@link LockSupport#park() LockSupport.park}</li>
   * </ul>
   *
   * <p>A thread in the waiting state is waiting for another thread to
   * perform a particular action.
   *
   * For example, a thread that has called <tt>Object.wait()</tt>
   * on an object is waiting for another thread to call
   * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
   * that object. A thread that has called <tt>Thread.join()</tt>
   * is waiting for a specified thread to terminate.
   */
  WAITING,

  /**
   * Thread state for a waiting thread with a specified waiting time.
   * A thread is in the timed waiting state due to calling one of
   * the following methods with a specified positive waiting time:
   * <ul>
   *   <li>{@link #sleep Thread.sleep}</li>
   *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
   *   <li>{@link #join(long) Thread.join} with timeout</li>
   *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
   *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
   * </ul>
   */
  TIMED_WAITING,

  /** * Thread state for a terminated thread. * The thread has completed execution. */
  TERMINATED;
}
Copy the code

To check thread status and JVM memory monitoring, use the following command:

  • JPS: View the process information in Java on the machine

  • Dump (jstack pid< process id>)

  • Jmap: Dump (format-b,file= save file path)

  • Jstat: performance monitoring tool

  • Jhat: jhat -port file

  • Jconsole: Simple visual console

  • Jvisualvm: Powerful console

Thread creation

  • Inheriting the Thread class (essentially an implementation of the Runnable interface)
  • Implement the Runnable interface
  • Use the ExecutorService
  • Callable, Future (with return value)

The only way to start a Thread is through the Thread class’s start method (srart is a native method that starts a new Thread and executes the run method)

/** Thread class source code */
public class Thread implements Runnable {
  /* Make sure registerNatives is the first thing <clinit> does. */
  private static native void registerNatives(a);
  static {
    registerNatives();
  }

  /* What will be run. */
  private Runnable target;
  
  public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
  }
  
  public Thread(Runnable target, String name) {
    init(null, target, name, 0);
  }
  
  public synchronized void start(a) {
    /** * This method is not invoked for the main method thread or "system" * group threads created/set up by the VM. Any new functionality added * to this method in the future may have to also be added to the VM. * * A zero status value corresponds to state "NEW". */
    if(threadStatus ! =0)
      throw new IllegalThreadStateException();

    /* Notify the group that this thread is about to be started * so that it can be added to the group's list of threads * and the group's unstarted count can be decremented. */
    group.add(this);

    boolean started = false;
    try {
      start0();
      started = true;
    } finally {
      try {
        if(! started) { group.threadStartFailed(this); }}catch (Throwable ignore) {
        /* do nothing. If start0 threw a Throwable then it will be passed up the call stack */}}}/** native method */
  private native void start0(a);

  @Override
  public void run(a) {
    if(target ! =null) { target.run(); }}}Copy the code

JVM thread creation, start source code

Open its/jdk8 / jdk8 / JDK source code, find the file – > SRC/share/native/Java/lang/Thread. @ 2362 c: 00 cd9dc3c2b5, you can see in Java Thread class call native methods, Defined in the virtual machine jvm.cpp file, as well as mapping relationships, local methods are exposed to external calls through JNI technology.

Thread. C

#include "jni.h"
#include "jvm.h"
#include "java_lang_Thread.h"

#define THD "Ljava/lang/Thread;"
#define OBJ "Ljava/lang/Object;"
#define STE "Ljava/lang/StackTraceElement;"
#define ARRAY_LENGTH(a) (sizeof(a)/sizeof(a[0]))

static JNINativeMethod methods[] = {
    {"start0"."()V",        (void *)&JVM_StartThread},
    {"stop0"."(" OBJ ")V", (void *)&JVM_StopThread},
    {"isAlive"."()Z",        (void *)&JVM_IsThreadAlive},
    {"suspend0"."()V",        (void *)&JVM_SuspendThread},
    {"resume0"."()V",        (void *)&JVM_ResumeThread},
    {"setPriority0"."(I)V",       (void *)&JVM_SetThreadPriority},
    {"yield"."()V",        (void *)&JVM_Yield},
    {"sleep"."(J)V",       (void *)&JVM_Sleep},
    {"currentThread"."()" THD,     (void *)&JVM_CurrentThread},
    {"countStackFrames"."()I",        (void *)&JVM_CountStackFrames},
    {"interrupt0"."()V",        (void *)&JVM_Interrupt},
    {"isInterrupted"."(Z)Z",       (void *)&JVM_IsInterrupted},
    {"holdsLock"."(" OBJ ")Z", (void *)&JVM_HoldsLock},
    {"getThreads"."()" THD,   (void *)&JVM_GetAllThreads},
    {"dumpThreads"."([" THD "The [[" STE, (void *)&JVM_DumpThreads},
};

#undef THD
#undef OBJ
#undef STE

JNIEXPORT void JNICALL
Java_java_lang_Thread_registerNatives(JNIEnv *env, jclass cls)
{
    (*env)->RegisterNatives(env, cls, methods, ARRAY_LENGTH(methods));
}
Copy the code

/ SRC/share/vm/prims/JVM. CPP source (thread) :

JVM_ENTRY(void.JVM_StartThread(JNIEnv* env, jobject jthread))
  JVMWrapper("JVM_StartThread");
  JavaThread *native_thread = NULL;

  // We cannot hold the Threads_lock when we throw an exception,
  // due to rank ordering issues. Example: we might need to grab the
  // Heap_lock while we construct the exception.
  bool throw_illegal_thread_state = false;

  // We must release the Threads_lock before we can post a jvmti event
  // in Thread::start.
  {
    // Ensure that the C++ Thread and OSThread structures aren't freed before
    // we operate.
    MutexLocker mu(Threads_lock);

    // Since JDK 5 the java.lang.Thread threadStatus is used to prevent
    // re-starting an already started thread, so we should usually find
    // that the JavaThread is null. However for a JNI attached thread
    // there is a small window between the Thread object being created
    // (with its JavaThread set) and the update to its threadStatus, so we
    // have to check for this
    if (java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread)) ! =NULL) {
      throw_illegal_thread_state = true;
    } else {
      // We could also check the stillborn flag to see if this thread was already stopped, but
      // for historical reasons we let the thread detect that itself when it starts running

      jlong size =
             java_lang_Thread::stackSize(JNIHandles::resolve_non_null(jthread));
      // Allocate the C++ Thread structure and create the native thread. The
      // stack size retrieved from java is signed, but the constructor takes
      // size_t (an unsigned type), so avoid passing negative values which would
      // result in really large stacks.
      size_t sz = size > 0 ? (size_t) size : 0;
      native_thread = new JavaThread(&thread_entry, sz);

      // At this point it may be possible that no osthread was created for the
      // JavaThread due to lack of memory. Check for this situation and throw
      // an exception if necessary. Eventually we may want to change this so
      // that we only grab the lock if the thread was created successfully -
      // then we can also do this check and throw the exception in the
      // JavaThread constructor.
      if (native_thread->osthread() != NULL) {
        // Note: the current thread is not being used within "prepare".
        native_thread->prepare(jthread); }}}if (throw_illegal_thread_state) {
    THROW(vmSymbols::java_lang_IllegalThreadStateException());
  }

  assert(native_thread ! =NULL."Starting null thread?");

  if (native_thread->osthread() = =NULL) {
    // No one should hold a reference to the 'native_thread'.
    delete native_thread;
    if (JvmtiExport::should_post_resource_exhausted()) {
      JvmtiExport::post_resource_exhausted(
        JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR | JVMTI_RESOURCE_EXHAUSTED_THREADS,
        "unable to create new native thread");
    }
    THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(),
              "unable to create new native thread");
  }

  Thread::start(native_thread);

JVM_END
Copy the code

Native_thread = new JavaThread(&thread_entry, sz); Native_thread is created by creating a JAVA Thread, starting the Thread with Thread::start(native_thread), and eventually creating the Thread with the operating system.

/ SRC/share/vm/runtime/thread. The CPP source code:

void Thread::start(Thread* thread) {
  trace("start", thread);
  // Start is different from resume in that its safety is guaranteed by context or
  // being called from a Java method synchronized on the Thread object.
  if(! DisableStartThread) {if (thread->is_Java_thread()) {
      // Initialize the thread state to RUNNABLE before starting this thread.
      // Can not set it after the thread started because we do not know the
      // exact thread state at that time. It could be in MONITOR_WAIT or
      // in SLEEPING or some other state.
      java_lang_Thread::set_thread_status(((JavaThread*)thread)->threadObj(),
                                          java_lang_Thread::RUNNABLE);
    }
    os::start_thread(thread); }}Copy the code

JVM interrupts thread methods

/ SRC/share/vm/prims/JVM. CPP source code, the JVM. Finally the Thread of the CPP is_interrupted way to interrupt a Thread

JVM_ENTRY(void.JVM_Interrupt(JNIEnv* env, jobject jthread))
  JVMWrapper("JVM_Interrupt");

  // Ensure that the C++ Thread and OSThread structures aren't freed before we operate
  oop java_thread = JNIHandles::resolve_non_null(jthread);
  MutexLockerEx ml(thread->threadObj() == java_thread ? NULL : Threads_lock);
  // We need to re-resolve the java_thread, since a GC might have happened during the
  // acquire of the lock
  JavaThread* thr = java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread));
  if(thr ! =NULL) {
    Thread::interrupt(thr);
  }
JVM_END

JVM_QUICK_ENTRY(jboolean, JVM_IsInterrupted(JNIEnv* env, jobject jthread, jboolean clear_interrupted))
  JVMWrapper("JVM_IsInterrupted");

  // Ensure that the C++ Thread and OSThread structures aren't freed before we operate
  oop java_thread = JNIHandles::resolve_non_null(jthread);
  MutexLockerEx ml(thread->threadObj() == java_thread ? NULL : Threads_lock);
  // We need to re-resolve the java_thread, since a GC might have happened during the
  // acquire of the lock
  JavaThread* thr = java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread));
  if (thr == NULL) {
    return JNI_FALSE;
  } else {
    return (jboolean) Thread::is_interrupted(thr, clear_interrupted ! =0);
  }
JVM_END
Copy the code

/ SRC/share/vm/runtime/thread. The CPP source code, in the end is is_interrupted way to invoke the operating system interrupt threads

void Thread::interrupt(Thread* thread) {
  trace("interrupt", thread);
  debug_only(check_for_dangling_thread_pointer(thread);)
  os::interrupt(thread);
}

bool Thread::is_interrupted(Thread* thread, bool clear_interrupted) {
  trace("is_interrupted", thread);
  debug_only(check_for_dangling_thread_pointer(thread);)
  // Note: If clear_interrupted==false, this simply fetches and
  // returns the value of the field osthread()->interrupted().
  return os::is_interrupted(thread, clear_interrupted);
}
Copy the code

/ SRC/OS/Linux /vm/os_linux.cpp: set_interrupted(true) ¶ The default is false

void os::interrupt(Thread* thread) {
  assert(Thread::current() == thread || Threads_lock->owned_by_self(),
    "possibility of dangling Thread pointer");

  OSThread* osthread = thread->osthread(a);if(! osthread->interrupted()) {
    osthread->set_interrupted(true);
    // More than one thread can get here with the same value of osthread,
    // resulting in multiple notifications. We do, however, want the store
    // to interrupted() to be visible to other threads before we execute unpark().
    OrderAccess::fence(a); ParkEvent *const slp = thread->_SleepEvent ;
    if(slp ! =NULL) slp->unpark() ;
  }

  // For JSR166. Unpark even if interrupt status already was set
  if (thread->is_Java_thread())
    ((JavaThread*)thread)->parker() - >unpark(a); ParkEvent * ev = thread->_ParkEvent ;if(ev ! =NULL) ev->unpark() ;

}

bool os::is_interrupted(Thread* thread, bool clear_interrupted) {
  assert(Thread::current() == thread || Threads_lock->owned_by_self(),
    "possibility of dangling Thread pointer");

  OSThread* osthread = thread->osthread(a);bool interrupted = osthread->interrupted(a);if (interrupted && clear_interrupted) {
    osthread->set_interrupted(false);
    // consider thread->_SleepEvent->reset() ... optional optimization
  }

  return interrupted;
}
Copy the code

/ SRC/share/vm/runtime/osThread HPP source code

class OSThread: public CHeapObj<mtThread> {
 friend class VMStructs;
 private:
  /** omit other code */
  volatile ThreadState _state;    // Thread state *hint*
  volatile jint _interrupted;     // Thread.isInterrupted state

  // Note: _interrupted must be jint, so that Java intrinsics can access it.
  // The value stored there must be either 0 or 1. It must be possible
  // for Java to emulate Thread.currentThread().isInterrupted() by performing
  // the double indirection Thread::current()->_osthread->_interrupted.

  // Methods
 public:
  void set_state(ThreadState state)                { _state = state; }
  ThreadState get_state(a)                          { return _state; }

  /** omit other code */

  volatile bool interrupted(a) const                 { return_interrupted ! =0; }
  void set_interrupted(bool z)                      { _interrupted = z ? 1 : 0; }
  
  / * *...... The rest of the code omits */
}
Copy the code

The Thread Interrupte calls Thread.interrupted() to restore

Thread.java

Thread.interrupted();  // Reset to the initial state

public static boolean interrupted(a) {
  return currentThread().isInterrupted(true);
}

// Local methods, refer to the JVM thread interrupt source code already mentioned above
private native boolean isInterrupted(boolean ClearInterrupted);
Copy the code

Interrupt a blocked state (sleep/wait/join/…) (see the JVM_Sleep method in the jvm. CPP file for why an exception was thrown)

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

  // Save current thread state and restore it at the end of this block.
  // And set new thread state to SLEEPING.
  JavaThreadSleepState jtss(thread);

#ifndef USDT2
  HS_DTRACE_PROBE1(hotspot, thread__sleep__begin, millis);
#else /* USDT2 */
  HOTSPOT_THREAD_SLEEP_BEGIN(
                             millis);
#endif /* USDT2 */

  EventThreadSleep event;

  if (millis == 0) {
    // When ConvertSleepToYield is on, this matches the classic VM implementation of
    // JVM_Sleep. Critical for similar threading behaviour (Win32)
    // It appears that in certain GUI contexts, it may be beneficial to do a short sleep
    // for SOLARIS
    if (ConvertSleepToYield) {
      os::yield(a); }else {
      ThreadState old_state = thread->osthread() - >get_state(a); thread->osthread() - >set_state(SLEEPING);
      os::sleep(thread, MinSleepInterval, false);
      thread->osthread() - >set_state(old_state); }}else {
    ThreadState old_state = thread->osthread() - >get_state(a); thread->osthread() - >set_state(SLEEPING);
    if (os::sleep(thread, millis, true) == OS_INTRPT) {
      // An asynchronous exception (e.g., ThreadDeathException) could have been thrown on
      // us while we were sleeping. We do not overwrite those.
      if(! HAS_PENDING_EXCEPTION) {if (event.should_commit()) {
          event.set_time(millis);
          event.commit(a); }#ifndef USDT2
        HS_DTRACE_PROBE1(hotspot, thread__sleep__end,1);
#else /* USDT2 */
        HOTSPOT_THREAD_SLEEP_END(
                                 1);
#endif /* USDT2 */
        // TODO-FIXME: THROW_MSG returns which means we will not call set_state()
        // to properly restore the thread state. That's likely wrong.
        THROW_MSG(vmSymbols::java_lang_InterruptedException(), "sleep interrupted");
      }
    }
    thread->osthread() - >set_state(old_state);
  }
  if (event.should_commit()) {
    event.set_time(millis);
    event.commit(a); }#ifndef USDT2
  HS_DTRACE_PROBE1(hotspot, thread__sleep__end,0);
#else /* USDT2 */
  HOTSPOT_THREAD_SLEEP_END(
                           0);
#endif /* USDT2 */
JVM_END
Copy the code

The practical application

  • The thread pool
  • Zookeeper responsibility chain asynchronizes tasks
  • Run batch scripts and reconciliation files