線程啟動(dòng):源碼的理解

線程 調(diào)用 star() 的過程分析:

  public static void main(String[] args) {
        new Thread(()->{
            System.out.println("啟動(dòng)一個(gè)新的線程"+Thread.currentThread().getName());
        }).start();
    }
啟動(dòng)一個(gè)新的線程Thread-0
Process finished with exit code 0

當(dāng) Java 線程創(chuàng)建好后,調(diào)用 start() 方法就會(huì)啟動(dòng)一個(gè)線程柳弄,那 start() 是怎么實(shí)現(xiàn)的呢舶胀?源碼如下:

    public synchronized void start() {
        /**
         * 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 */
            }
        }
    }

分析以上代碼 發(fā)現(xiàn) 最終調(diào)用了 start0()這個(gè)方法,找到 start0();代碼:

private native void start0();

原來是 native方法语御,打開 jdk 源碼 找到 start0定義和實(shí)現(xiàn):

static JNINativeMethod methods[] = {
    {"start0",           "()V",        (void *)&JVM_StartThread},
    {"stop0",            "(" OBJ ")V", (void *)&JVM_StopThread},
    {"isAlive",          "()Z",        (void *)&JVM_IsThreadAlive},
};

JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) :
  Thread()
#if INCLUDE_ALL_GCS
  , _satb_mark_queue(&_satb_mark_queue_set),
  _dirty_card_queue(&_dirty_card_queue_set)
#endif // INCLUDE_ALL_GCS
{
  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;

  // 創(chuàng)建線程                                              
  os::create_thread(this, thr_type, stack_sz);
  _safepoint_visible = false;
  // The _osthread may be NULL here because we ran out of memory (too many threads active).
  // We need to throw and OutOfMemoryError - however we cannot do this here because the caller
  // may hold a lock and all locks must be unlocked before throwing the exception (throwing
  // the exception consists of creating the exception object & initializing it, initialization
  // will leave the VM via a JavaCall and then all locks must be unlocked).
  //
  // The thread is still suspended when we reach here. Thread must be explicit started
  // by creator! Furthermore, the thread must also explicitly be added to the Threads list
  // by calling Threads:add. The reason why this is not done here, is because the thread
  // object must be fully initialized (take a look at JVM_Start)
}

通過閱讀以上代碼發(fā)現(xiàn) os::create_thread(this, thr_type, stack_sz); 才是調(diào)用系統(tǒng)內(nèi)核創(chuàng)建線程,找到對(duì)應(yīng)Linux 線程創(chuàng)建實(shí)現(xiàn):

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

峻贮。。应闯。。挂捻。碉纺。
    // 創(chuàng)建線程
    int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread);
 。刻撒。骨田。。声怔。态贤。

  assert(state == INITIALIZED, "race condition");
  return true;
}

通過閱讀以上代碼 發(fā)現(xiàn) 主要就 通過 pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread)來創(chuàng)建線程,第三個(gè)參數(shù)是線程運(yùn)行函數(shù)的地址醋火,最后一個(gè)參數(shù)是運(yùn)行函數(shù)的參數(shù)悠汽。pthread_create 定義

static void *java_start(Thread *thread) {
  // Try to randomize the cache line index of hot stack frames.
  // This helps when threads of the same stack traces evict each other's
  // cache lines. The threads can be either from the same JVM instance, or
  // from different JVM instances. The benefit is especially true for
  // processors with hyperthreading technology.
  static int counter = 0;
  int pid = os::current_process_id();
  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());

  if (UseNUMA) {
    int lgrp_id = os::numa_get_group_id();
    if (lgrp_id != -1) {
      thread->set_lgrp_id(lgrp_id);
    }
  }
  // initialize signal mask for this thread
  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);

    // notify parent thread
    osthread->set_state(INITIALIZED);
    sync->notify_all();

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

  // call one more level start routine
  // 調(diào)用JavaThread::run()方法
  thread->run();
  return 0;
}

通過以上代碼發(fā)現(xiàn) 最后調(diào)用 thread->run(); 找到對(duì)應(yīng)的實(shí)現(xiàn):

void JavaThread::run() {
  // initialize thread-local alloc buffer related fields
  // 初始化Thread_local 
  this->initialize_tlab();

  // used to test validitity of stack trace backs
  this->record_base_of_stack_pointer();

  // Record real stack base and size.
  this->record_stack_base_and_size();

  // Initialize thread local storage; set before calling MutexLocker
  // 初始化 ThreadLocal 存儲(chǔ)
  this->initialize_thread_local_storage();

  this->create_stack_guard_pages();

  this->cache_global_variables();

  // Thread is now sufficient initialized to be handled by the safepoint code as being
  // in the VM. Change thread state from _thread_new to _thread_in_vm
  ThreadStateTransition::transition_and_fence(this, _thread_new, _thread_in_vm);

  assert(JavaThread::current() == this, "sanity check");
  assert(!Thread::current()->owns_locks(), "sanity check");

  DTRACE_THREAD_PROBE(start, this);

  // This operation might block. We call that after all safepoint checks for a new thread has
  // been completed.
  this->set_active_handles(JNIHandleBlock::allocate_block());

  if (JvmtiExport::should_post_thread_life()) {
    JvmtiExport::post_thread_start(this);
  }

  EventThreadStart event;
  if (event.should_commit()) {
     event.set_javalangthread(java_lang_Thread::thread_id(this->threadObj()));
     event.commit();
  }

  // We call another function to do the rest so we are sure that the stack addresses used
  // from there will be lower than the stack base just computed

  //  判斷 run() 是否執(zhí)行完畢,然后退出線程
  thread_main_inner();
}

通過閱讀以上代碼發(fā)現(xiàn):程序在最后執(zhí)行 thread_main_inner(); 該 方法 主要書判斷 當(dāng)前線程 是否執(zhí)行完畢芥驳,如果執(zhí)行完畢柿冲,清除線程,并喚醒等待線程隊(duì)列中的一個(gè)線程兆旬。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載假抄,如需轉(zhuǎn)載請(qǐng)通過簡信或評(píng)論聯(lián)系作者。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市宿饱,隨后出現(xiàn)的幾起案子熏瞄,更是在濱河造成了極大的恐慌,老刑警劉巖谬以,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件巴刻,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蛉签,警方通過查閱死者的電腦和手機(jī)胡陪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來碍舍,“玉大人柠座,你說我怎么就攤上這事∑穑” “怎么了妈经?”我有些...
    開封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長捧书。 經(jīng)常有香客問我吹泡,道長,這世上最難降的妖魔是什么经瓷? 我笑而不...
    開封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任爆哑,我火速辦了婚禮,結(jié)果婚禮上舆吮,老公的妹妹穿的比我還像新娘揭朝。我一直安慰自己,他們只是感情好色冀,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開白布潭袱。 她就那樣靜靜地躺著,像睡著了一般锋恬。 火紅的嫁衣襯著肌膚如雪屯换。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天与学,我揣著相機(jī)與錄音彤悔,去河邊找鬼。 笑死癣防,一個(gè)胖子當(dāng)著我的面吹牛蜗巧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蕾盯,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼幕屹,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼蓝丙!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起望拖,我...
    開封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤渺尘,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后说敏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鸥跟,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年盔沫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了医咨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡架诞,死狀恐怖拟淮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情谴忧,我是刑警寧澤很泊,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站沾谓,受9級(jí)特大地震影響委造,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜均驶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一昏兆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧辣恋,春花似錦亮垫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽燃异。三九已至携狭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間回俐,已是汗流浹背逛腿。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留仅颇,地道東北人单默。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像忘瓦,于是被迫代替她去往敵國和親搁廓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355