Java线程的底层原理

线程

线程是CPU独立调度的单位,通过引入线程,实现时分复用,利用并发思想使我们的程序运行的更加迅速。

线程与语言无关,由操作系统来实现,主要有3种实现方式:

  1. 用户级线程
  2. 内核级线程
  3. 用户级线程+内核级线程

内核线程

内核线程就是直接由操作系统内核支持的线程,这种线程由内核来完成线程切换。

用户线程

一个线程只要不是内核线程,就可以认为是用户线程。

Java线程

Java线程是映射到操作系统的内核线程上的。

要启动一个Java线程,主要有两种方式:

  1. 继承Thread
  2. 实现Runnable
package com.doaredo.test;

public class ThreadDemo {
    public static void main(String[] args) {
        ThreadA threadA = new ThreadA();
        threadA.start();

        Thread threadB = new Thread(new ThreadB());
        threadB.start();

        new Thread(()->{
            System.out.println("jdk1.8 thread...");
        }).start();
    }
}

class ThreadA extends Thread {
    @Override
    public void run() {
        System.out.println("ThreadA run...");
    }
}

class ThreadB implements Runnable {
    @Override
    public void run() {
        System.out.println("ThreadB run...");
    }
}

很多同学都会纠结到底使用哪种方式好,这样说吧,如果你只是单纯的想创建一个线程,那么就实现Runnable,如果除了创建线程,还想使用一些其他的功能,那么就继承Thread,因为继承Thread,你可以获得它提供的一些你想使用的功能。

真正启动线程靠的是start()方法,我们可以看到最终是调用的一个start0()的native方法。

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

    private native void start0();

既然是native方法,那么肯定就是由C、C++来实现了。下面为Thread的定义:openjdk/jdk/src/share/native/java/lang/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},
};

上面定义了一个数组,数组中存放的为JNINativeMethod类型的结构体变量,而JNINativeMethod定义在openjdk/hotspot/src/share/vm/prims/jni.h中

typedef struct {
    char *name;
    char *signature;
    void *fnPtr;
} JNINativeMethod;

JNINativeMethod主要是处理jni native方法的映射关系,将native方法和真正的实现方法进行绑定。java层的Thread在静态块中,调用了registerNatives()方法。

private static native void registerNatives();
    static {
        registerNatives();
    }

而registerNatives()也是一个native方法,具体实现在Thread.c中

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

具体的方法映射关系就是

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()方法,由前面的映射关系,我们可以知道start0对应的为JVM_StartThread,这个具体实现在jvm.cpp中

VM_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);

    // 判断线程是否已经启动,如果已经启动则会抛出异常
    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;
      // 创建Java线程
      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);
      }
    }
  }
 ......
  Thread::start(native_thread);

JVM_END

创建线程的构造方法在openjdk/hotspot/src/share/vm/runtime/thread.cpp中

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;
  os::create_thread(this, thr_type, stack_sz);
}

最后一句代码便是开始真正的创建Java线程对应的内核线程。

image-20210206234137169

不同的操作系统有不同的实现,以linux为例os_linux.cpp,在实现中调用了pthread_create来创建线程

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*)) java_start, thread);
    ......
    return true;
}

我们看pthread_create方法的java_start参数,该参数为线程函数的运行地址,最终会调用thread->run()。

static void *java_start(Thread *thread) {

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

  return 0;
}

thread->run()调用的就是thread.cpp中的JavaThread::run()

void JavaThread::run() {

  // 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
  thread_main_inner();

  // Note, thread is no longer valid at this point!
}

void JavaThread::thread_main_inner() {
  assert(JavaThread::current() == this, "sanity check");
  assert(this->threadObj() != NULL, "just checking");

  // Execute thread entry point unless this thread has a pending exception
  // or has been stopped before starting.
  // Note: Due to JVM_StopThread we can have pending exceptions already!
  if (!this->has_pending_exception() &&
      !java_lang_Thread::is_stillborn(this->threadObj())) {
    {
      ResourceMark rm(this);
      this->set_native_thread_name(this->get_thread_name());
    }
    HandleMark hm(this);
    this->entry_point()(this, this);
  }

  DTRACE_THREAD_PROBE(stop, this);

  this->exit(false);
  delete this;
}

this->entry_point()(this, this);这行代码最终执行的是jvm.cpp中的thread_entry(JavaThread* thread, TRAPS)

static void thread_entry(JavaThread* thread, TRAPS) {
  HandleMark hm(THREAD);
  Handle obj(THREAD, thread->threadObj());
  JavaValue result(T_VOID);
  JavaCalls::call_virtual(&result,
                          obj,
                          KlassHandle(THREAD, SystemDictionary::Thread_klass()),
                          vmSymbols::run_method_name(),
                          vmSymbols::void_method_signature(),
                          THREAD);
}

我们可以看到使用了JavaCalls,也就是调用Java层的run()方法。

总结

  1. Thread.start()调用native的start0()
  2. JVM通过pthread_create()创建一个系统内核线程
  3. 在内核线程的运行方法中,利用JavaCalls调用java线程的run()方法

Java线程

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值