Java線程源碼分析

Java線程源碼分析

  1. java.lang.Thread主要的成員變量如下:
private char name[];//線程名稱
private int priority;//優先級
private volatile int threadStatus = 0;//線程狀態
private boolean daemon = false;//是否後臺線程
private Runnable target;//線程執行的邏輯
   //每個線程都有一個ThreadLocalMap的成員變量,類似hashmap
ThreadLocal.ThreadLocalMap threadLocals = null;
private long  eetop;//實際上是個指針,指向JavaThread的地址
  1. start()方法
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) {
            }
        }
    }

    private native void start0();
  1. star0()的實現, 查看Thread.c文件可以知道,它實際上調用的是jvm.cpp文件的JVM_StartThread方法:
JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))
  JVMWrapper("JVM_StartThread");
  JavaThread *native_thread = NULL;

  bool throw_illegal_thread_state = false;
  {
   // Threads_lock代表在活動線程表上的鎖,MutexLocker會調用lock方法上鎖
    MutexLocker mu(Threads_lock);
    //實際上是判斷java.lang.Thread的eetop,正常情況下,在後續步驟中會賦值,但在此處爲0,不指向任何對象;
    //其實在start方法中已經根據threadStatus進行了判斷,但是由於創建線程對象和更新threadStatus並不是原子操作,因而再次check
    if (java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread)) != NULL) {
      throw_illegal_thread_state = true;//狀態錯誤,返回
    } else {
     //在java.lang.Thread的init方法中,可設置stack的大小,此處獲取設置的大小;
     //不過通常調用構造函數的時候都不會傳入stack大小,size=0
      jlong size =
        java_lang_Thread::stackSize(JNIHandles::resolve_non_null(jthread));
      size_t sz = size > 0 ? (size_t) size : 0;
     //在下面的[創建JavaThread]介紹
      native_thread = new JavaThread(&thread_entry, sz);
      if (native_thread->osthread() != NULL) {
        native_thread->prepare(jthread);
      }
    }
  }

  if (throw_illegal_thread_state) {
    THROW(vmSymbols::java_lang_IllegalThreadStateException());
  }

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

  //Java線程實際上是通過系統線程實現的,如果創建系統線程失敗,報錯;
  //有很多原因會導致該錯誤:比如內存不足、max user processes設置過小 
  if (native_thread->osthread() == NULL) {
    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");
  }
  //在下面的[創建JavaThread]介紹
  Thread::start(native_thread);

JVM_END
  1. 創建JavaThread
JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) :
  Thread()
#ifndef SERIALGC
  , _satb_mark_queue(&_satb_mark_queue_set),
  _dirty_card_queue(&_dirty_card_queue_set)
#endif // !SERIALGC
{
  if (TraceThreadEvents) {
    tty->print_cr("creating thread %p", this);
  }
  initialize();
  _jni_attach_state = _not_attaching_via_jni;
  set_entry_point(entry_point);
 
  os::ThreadType thr_type = os::java_thread;
  //根據entry_point判斷是CompilerThread還是JavaThread
  //由於此處傳入的爲&thread_entry,因此爲os::java_thread
  thr_type = entry_point == &compiler_thread_entry ? os::compiler_thread :
                             os::java_thread;
 // os線程有可能創建失敗,在上文已經看到對該場景的處理
  os::create_thread(this, thr_type, stack_sz);
  _safepoint_visible = false;
}
  1. create_thread方法
bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) {
  assert(thread->osthread() == NULL, "caller responsible");

  // 創建OSThread
  OSThread* osthread = new OSThread(NULL, NULL);
  if (osthread == NULL) {
    return false;
  }
  //設置線程類型
  osthread->set_thread_type(thr_type);

  // 初始化狀態爲ALLOCATED
  osthread->set_state(ALLOCATED);
  thread->set_osthread(osthread);
  //linux下可以通過pthread_attr_t來設置線程屬性
  pthread_attr_t attr;
  pthread_attr_init(&attr);//linux系統調用,更多內容請參考內核文檔
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

  // 線程棧大小
  if (os::Linux::supports_variable_stack_size()) {//是否支持設置棧大小
    //如果用戶創建線程時未指定棧大小,對於JavaThread會看是否設置了-Xss或ThreadStackSize;
    //如果未設置,則採用系統默認值。對於64位操作系統,默認爲1M;
    //操作系統棧大小(ulimit -s):這個配置隻影響進程的初始線程;後續用pthread_create創建的線程都可以指定棧大小。
    //HotSpot VM爲了能精確控制Java線程的棧大小,特意不使用進程的初始線程(primordial thread)作爲Java線程
    if (stack_size == 0) {
      stack_size = os::Linux::default_stack_size(thr_type);
      switch (thr_type) {
      case os::java_thread:
      //讀取Xss和ThreadStackSize
        assert (JavaThread::stack_size_at_create() > 0, "this should be set");
        stack_size = JavaThread::stack_size_at_create();
        break;
      case os::compiler_thread:
        if (CompilerThreadStackSize > 0) {
          stack_size = (size_t)(CompilerThreadStackSize * K);
          break;
        } // else fall through:
          // use VMThreadStackSize if CompilerThreadStackSize is not defined
      case os::vm_thread:
      case os::pgc_thread:
      case os::cgc_thread:
      case os::watcher_thread:
        if (VMThreadStackSize > 0) stack_size = (size_t)(VMThreadStackSize * K);
        break;
      }
    }
   //棧最小爲48k
    stack_size = MAX2(stack_size, os::Linux::min_stack_allowed);
    pthread_attr_setstacksize(&attr, stack_size);
  } else {
    // let pthread_create() pick the default value.
  }

  pthread_attr_setguardsize(&attr, os::Linux::default_guard_size(thr_type));

  ThreadState state;
  {
   //如果linux線程而且不支持設置棧大小,則先獲取創建線程鎖,獲取鎖之後再創建線程
    bool lock = os::Linux::is_LinuxThreads() && !os::Linux::is_floating_stack();
    if (lock) {
      os::Linux::createThread_lock()->lock_without_safepoint_check();
    }

    pthread_t tid;
    //調用linux的pthread_create創建線程,傳入4個參數
    //第一個參數:指向線程標示符pthread_t的指針;
    //第二個參數:設置線程的屬性
    //第三個參數:線程運行函數的起始地址
    //第四個參數:運行函數的參數
    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;
    }

    // 將pthread id保存到osthread
    osthread->set_pthread_id(tid);

    // 等待pthread_create創建的子線程完成初始化或放棄
    {
      Monitor* sync_with_child = osthread->startThread_lock();
      MutexLockerEx ml(sync_with_child, Mutex::_no_safepoint_check_flag);
      while ((state = osthread->get_state()) == ALLOCATED) {
        sync_with_child->wait(Mutex::_no_safepoint_check_flag);
      }
    }

    if (lock) {
      os::Linux::createThread_lock()->unlock();
    }
  }

  // Aborted due to thread limit being reached
  if (state == ZOMBIE) {
      thread->set_osthread(NULL);
      delete osthread;
      return false;
  }

  // The thread is returned suspended (in state INITIALIZED),
  // and is started higher up in the call chain
  assert(state == INITIALIZED, "race condition");
  return true;
}
  1. 創建線程時傳入了java_start,做爲線程運行函數的初始地址:
static void *java_start(Thread *thread) {
  static int counter = 0;
  int pid = os::current_process_id();
 //alloca是用來分配存儲空間的,它和malloc的區別是它是在當前函數的棧上分配存儲空間,而不是在堆中。
 //其優點是:當函數返回時,自動釋放它所使用的棧。
  alloca(((pid ^ counter++) & 7) * 128);

  ThreadLocalStorage::set_thread(thread);

  OSThread* osthread = thread->osthread();
  Monitor* sync = osthread->startThread_lock();

  // non floating stack LinuxThreads needs extra check, see above
  if (!_thread_safety_check(thread)) {
    // notify parent thread
    MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);
    osthread->set_state(ZOMBIE);
    sync->notify_all();
    return NULL;
  }

  // thread_id is kernel thread id (similar to Solaris LWP id)
  osthread->set_thread_id(os::Linux::gettid());

 //優先嚐試在請求線程當前所處的CPU的Local內存上分配空間。
 //如果local內存不足,優先淘汰local內存中無用的Page
  if (UseNUMA) {//默認爲false
    int lgrp_id = os::numa_get_group_id();
    if (lgrp_id != -1) {
      thread->set_lgrp_id(lgrp_id);
    }
  }
  // 調用pthread_sigmask初始化signal mask:VM線程處理BREAK_SIGNAL信號
  os::Linux::hotspot_sigmask(thread);

  // initialize floating point control register
  os::Linux::init_thread_fpu_state();

  // handshaking with parent thread
  {
    MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);

    // 設置狀態會INITIALIZED,並通過notify_all喚醒父線程
    osthread->set_state(INITIALIZED);
    sync->notify_all();

    // 一直等待父線程調用 os::start_thread()
    while (osthread->get_state() == INITIALIZED) {
      sync->wait(Mutex::_no_safepoint_check_flag);
    }
  }

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

  return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章