자바 동시성 시리즈 - 스레드 시작 프로세스의 JVM에 대한 심층 이해

머리말

최근 동시에서 시작할 준비가 주제를 엽니 다 좋아 notes'd 구성 할 수 있습니다. 동시 조각, 시작 AQS의 생각을 시작하는 곳에서, 자신, 새로운 아이디어가있다을 완료하기 전에 오픈 JDK 디버깅 시간을 컴파일 노트의 일부를 볼 수 있었던, 가장 기본적인 시작과 함께 시작하고이를 보내하기로 결정 하지 스레드, 우리는 JDK를 결합, 핫스팟 탐험 어떤 스레드의 기능과 아웃.
스레드 정의 : 가장 작은 단위 실행이 과정에 포함되어 있습니다.

자바 스레드

class Thread implements Runnable {
    /* Make sure registerNatives is the first thing <clinit> does. */
    private static native void registerNatives();
    static {
        registerNatives();
    }
    ...//省略一大波代码,和一些英文注释
    public synchronized void start() {
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        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 */
            }
        }
    }

보통 우리는 시작 스레드 () 메서드 호출 사용,
우리가 start () 메서드를 볼 수 있습니다 위의 스레드 소스 구조에서
새로운 상태가 아닌 경우, 예외 스레드 상태를 던져 여부를 결정,
실행 다음 start0을 () 이러한 로컬 방법

JVM 정의 스레드

의는 JDK의 지역 오픈 JDK 공개 방법, 개방 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 STR "Ljava/lang/String;"

#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 ")[[" STE, (void *)&JVM_DumpThreads},
    {"setNativeName",    "(" STR ")V", (void *)&JVM_SetNativeThreadName},
};

#undef THD
#undef OBJ
#undef STE
#undef STR

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

위의 코드는 한 뒤에 필요한 설명 경우는 매우 간단합니다, JNI의 관련에 등록,
의는 JVM_StartThread에 해당하는 JVM을 start0하는 방법을 찾도록
jvm.cpp에를

JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))
  JVMWrapper("JVM_StartThread");
  JavaThread *native_thread = NULL;
  // Heap_lock while we construct the exception.
  bool throw_illegal_thread_state = false;

  {
    MutexLocker mu(Threads_lock);

    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));
      size_t sz = size > 0 ? (size_t) size : 0;
      native_thread = new JavaThread(&thread_entry, sz);

      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

이, 우리는 단계 분석에 의해 단계를 주요 논리 가고있다

첫째, 뮤텍스 잠금을 획득

MutexLocker mu(Threads_lock);

상태가 시작되지 않도록하기 위해 스레드 상태를 확인

 if (java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread)) != NULL) {
      throw_illegal_thread_state = true;

이전 검사 장치는 주로 생성자 달성 JavaThread의 JVM을 만들고

native_thread = new JavaThread(&thread_entry, sz);

이 생성자의 주요 내용 봐

JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) :
  Thread()
  ...//省略
{
  if (TraceThreadEvents) {
    tty->print_cr("creating thread %p", this);
  }
  initialize();
  _jni_attach_state = _not_attaching_via_jni;
  set_entry_point(entry_point);
  // Create the native thread itself.
  // %note runtime_23
  os::ThreadType thr_type = os::java_thread;
  thr_type = entry_point == &compiler_thread_entry ? os::compiler_thread :
                                                     os::java_thread;
  os::create_thread(this, thr_type, stack_sz);

우리는 마지막 라인 운영 체제 : create_thread (이, thr_type, stack_sz)를 참조하십시오,이 스레드를 생성, 실제 시스템 레벨에 매핑됩니다.

bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) {
  assert(thread->osthread() == NULL, "caller responsible");

  // Allocate the OSThread object
  OSThread* osthread = new OSThread(NULL, NULL);
  if (osthread == NULL) {
    return false;
  }

  // set the correct thread state
  osthread->set_thread_type(thr_type);

  // Initial state is ALLOCATED but not INITIALIZED
  osthread->set_state(ALLOCATED);

  thread->set_osthread(osthread);
  ......//省略
    pthread_t tid;
    int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread);

    pthread_attr_destroy(&attr);

    if (ret != 0) {
      if (PrintMiscellaneous && (Verbose || WizardMode)) {
        perror("pthread_create()");
      }
      // Need to clean up stuff we've allocated so far
      thread->set_osthread(NULL);
      delete osthread;
      if (lock) os::Linux::createThread_lock()->unlock();
      return false;
    }

    // Store pthread info into the OSThread
    osthread->set_pthread_id(tid);

OS 레벨 스레드를 생성, JavaThread와 결합, 다음 그리기 초점

int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread);

java_start 새로 스레드 시작 항목을 만들어, 그것은 신호를 기다립니다은 () 메소드에서 자바를 실행 호출하려면
JVM을 구현 특정 로직 코드는 다음과 같이

  // wait until os::start_thread()
    while (osthread->get_state() == INITIALIZED) {
      sync->wait(Mutex::_no_safepoint_check_flag);
    }
  }

  // call one more level start routine
  thread->run()

결합 글의 자바 스레드 및 JVM에서뿐만 아니라, 시스템 레벨 스레드 결합하여 이전 단계, 다음으로 위로 JVM_StartThread있어서, 스레드가 생성되고, (jthread의) 조제 native_thread-> 통화.

마지막으로 정말 시작 스레드

Thread::start(native_thread);

다음 층에 의해 OS 레벨 스레드 층의 호출은 또한, 특정 논리는

void os::start_thread(Thread* thread) {
  // guard suspend/resume
  MutexLockerEx ml(thread->SR_lock(), Mutex::_no_safepoint_check_flag);
  OSThread* osthread = thread->osthread();
  osthread->set_state(RUNNABLE);
  pd_start_thread(thread);
}

이 시점에서, 우리는 정말 논리 스레드이었다 물론, 여전히 몇 가지 세부 사항 시스템 호출합니다. 이러한 방법으로 우리는 자바 레벨의 전체 스레드를 파악할 수, JVM 레벨은 후속 기사에서 O를 수준의 관계, 동시 시리즈 프라이머도 따라 할 수있는 좋은 장에서는 지식의 동시 조각을 이야기하는 것입니다 .

나는 또한 더 많은 콘텐츠에 맞게 조정 개별 사이트에 대한 걱정 : https://jie3615.github.io/


이 문서에서는 다시 인쇄에 오신 것을 환영합니다 저자 및 공동 소유의 정원 블로그에 속하지만이 부분에 의해 선언 된 저자의 동의없이 유지 및 기사 페이지의 명백한 위치에 원래 연결, 법적 책임을 추구하는 다른 권리를 부여해야합니다.

추천

출처www.cnblogs.com/jie3615/p/11272468.html