总结:线程之Java线程创建与启动流程

前言:Java创建线程,说白了就是创建一个linux的内核线程, 所以Java线程就是linux的内核线程,线程的管理基本上也就是操作系统在进行管理。那么java是如何从语言层面去让linux内核创建一个线程并让其运行,甚至控制其运行的优先级的?

一、浅层次的,对于我们开发人员来说, 想要启动一个Java线程,主要有两种方法,第一种可以实现一个继承自Thread的子类,重写run();第二种可以实现一个Runnable,交给Thread执行。然后 执行Thread.start() 才能真正的启动一个异步线程进行工作。

二、深层次的,我们通过追踪start()方法会发现,线程最终是调用一个native的start0()方法,所以想知道java如何启动一个线程,必须去看start0()是如何实现的。 Thread.c 中定义了java方法绑定的一些方法, Thread.c 中的一段定义 如下:

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

从上面我们能看到,start0绑定的方法为:JVM_StartThread,所以我们需要继续看JVM_StartThread方法。 JVM_StartThread定义在jvm.cpp中(.cpp是c++文件的后缀名,start0方法和C++的JVM_StartThread是通过JNI进行 方法的映射 , 将native方法和真正的实现方法进行绑定。 ):

JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))
  JVMWrapper("JVM_StartThread");
  JavaThread *native_thread = NULL;
  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 {
      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) {
        native_thread->prepare(jthread);
      }
    }
  }

  ......
  Thread::start(native_thread);

JVM_END

如上,我们看到两段关键的代码,分别是在C++中创建线程和启动线程:

1、native_thread = new JavaThread(&thread_entry, sz); //启动线程

2、Thread::start(native_thread);//让线程运行
上面的new JavaThread(&thread_entry, sz)看起来还不是最终的创建线程方法,我们再进去看下里面的方法:
JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) :
                       Thread()
{
  initialize();
  _jni_attach_state = _not_attaching_via_jni;
  set_entry_point(entry_point);
  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);//创建内核线程
}

终于找到了, 最后一句os::create_thread(this, thr_type, stack_sz) 便开始真正的创建Java线程对应的内核线程。

其实,也不是最终创建内核线程的方法,我们继续看下这个方法是怎么写的:

bool os::create_thread(Thread* thread, ThreadType thr_type,
                       size_t req_stack_size) {
    ......
    pthread_t tid;
    int ret = pthread_create(&tid, &attr, (void* (*)(void*)) thread_native_entry, thread);//创建线程
    ......
    return true;
}

上面这个方法主要就是利用pthread_create()来创建线程 ,其中第三个参数thread_native_entry便是新起的线程运行的初始地址,最后,通过调用Thread::start(native_thread);启动线程

总结

到这里Java线程就已经真正的运行起来了,总结下上面的过程:

1:调用Java线程start()方法,通过jni方式,调用到JVM层。

2:JVM通过pthread_create()创建一个系统内核线程,并指定内核线程的初始运行地址,即一个方法指针。

3:在内核线程的初始运行方法中,利用JavaCalls模块,调用java线程的run()方法,开始java级别的线程执行。


 

参考:

JVM之Java线程启动流程

JNI详解------完整Demo

JVM方法执行的来龙去脉

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值