Android中Thread.start干了什么

268 阅读6分钟

java.lang.Thread

什么是进程
什么是线程
进程和线程的区别
百度关键字已经写好,拿走不谢。

前文

在Android API 28 sdk中查看的Thread源码。
java sdk中的Thread源码和Android SDK中的有一定区别。
Android源码在线浏览:androidxref.com

Thread

java.lang包下的一个类,实现Runnable接口。
省略其他代码后就是下面的样子:

class Thread implements Runnable {

    private Runnable target;
    
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }
}

new Thread 做了什么

这里只分析 new Thread() 和 new Thread(mRunnable)

class Thread implements Runnable {

     private Runnable target;
     
     public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
     }
     
     public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
     }
    
     private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
        Thread parent = currentThread();//native方法,返回当前执行的线程对象的引用。
        if (g == null) {
            g = parent.getThreadGroup();
        }
        // 增加线程组中未启动线程的计数,
        // 未启动的线程不会添加到线程组中,以便在从未启动时可以收集它们,
        // 但必须对它们进行计数,以便不销毁其中包含未启动线程的守护进程线程组。
        g.addUnstarted();
        this.group = g;
        // 设置执行任务的target
        this.target = target;
        this.priority = parent.getPriority();
        // 设置是否是守护线程
        this.daemon = parent.isDaemon();
        // 设置线程名称
        setName(name);

        init2(parent);

        // 设置线程栈所需内存总大小
        this.stackSize = stackSize;
        // 生成并设置当前thread的id,
        // 注意此时执行的代码所在线程并非当前thread
        tid = nextThreadID();
     }
}

小结:
1. new Thread 只是在当前线程中创建了一个Thread类,并未开启一个新的线程。
2. Thread实现了Runnable中的run()方法;Thread(Runnable target)中的Runnable类只是用来设置Thread中的成员变量Runnable target。

Thread.start()做了什么

Thread.start()方法被调用时会创建一个新的线程

start()

public synchronized void start() {
    started = false;
    try {
        // 创建一个新的线程,并调用run()方法
        nativeCreate(this, stackSize, daemon);
        started = true;
    } finally {
        try {
            if (!started) {
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {
        }
    }
}

nativeCreate

nativeCreate 位于art/runtime/native/java_lang_Thread.cc,代码如下:

static void Thread_nativeCreate(JNIEnv* env, jclass, jobject java_thread, jlong stack_size,
                                jboolean daemon) {
  // There are sections in the zygote that forbid thread creation.
  // 在zygote中有些地方是禁止创建线程的
  Runtime* runtime = Runtime::Current();
  if (runtime->IsZygote() && runtime->IsZygoteNoThreadSection()) {
    jclass internal_error = env->FindClass("java/lang/InternalError");
    CHECK(internal_error != nullptr);
    env->ThrowNew(internal_error, "Cannot create threads in zygote");
    return;
  }
  //创建一个Native线程
  Thread::CreateNativeThread(env, java_thread, stack_size, daemon == JNI_TRUE);
}

CreateNativeThread

Thread::CreateNativeThread 位于/art/runtime/thread.cc,代码如下:

void Thread::CreateNativeThread(JNIEnv* env, jobject java_peer, size_t stack_size, bool is_daemon) {
  CHECK(java_peer != nullptr);
  Thread* self = static_cast<JNIEnvExt*>(env)->GetSelf();

  if (VLOG_IS_ON(threads)) {
    ScopedObjectAccess soa(env);

    ArtField* f = jni::DecodeArtField(WellKnownClasses::java_lang_Thread_name);
    ObjPtr<mirror::String> java_name =
        f->GetObject(soa.Decode<mirror::Object>(java_peer))->AsString();
    std::string thread_name;
    if (java_name != nullptr) {
      thread_name = java_name->ToModifiedUtf8();
    } else {
      thread_name = "(Unnamed)";
    }

    VLOG(threads) << "Creating native thread for " << thread_name;
    self->Dump(LOG_STREAM(INFO));
  }

  Runtime* runtime = Runtime::Current();

  // Atomically start the birth of the thread ensuring the runtime isn't shutting down.
  bool thread_start_during_shutdown = false;
  {
    MutexLock mu(self, *Locks::runtime_shutdown_lock_);
    if (runtime->IsShuttingDownLocked()) {
      thread_start_during_shutdown = true;
    } else {
      runtime->StartThreadBirth();
    }
  }
  if (thread_start_during_shutdown) {
    ScopedLocalRef<jclass> error_class(env, env->FindClass("java/lang/InternalError"));
    env->ThrowNew(error_class.get(), "Thread starting during runtime shutdown");
    return;
  }
  // 创建一个c类中的线程对象
  Thread* child_thread = new Thread(is_daemon);
  // 在子线程启动时,使用全局`JNI ref`保持对等线程处于活动状态。
  // 保证与child_thread对等的java对象(就是在java代码中new Thread出来的对象)是活动状态
  child_thread->tlsPtr_.jpeer = env->NewGlobalRef(java_peer);
  // 设置线程栈的大小,当传入的内存为0的时候,将会使用系统默认的大小。
  stack_size = FixStackSize(stack_size);

  // Thread.start is synchronized, so we know that nativePeer is 0, and know that we're not racing
  // to assign it.
  env->SetLongField(java_peer, WellKnownClasses::java_lang_Thread_nativePeer,
                    reinterpret_cast<jlong>(child_thread));

  // Try to allocate a JNIEnvExt for the thread. We do this here as we might be out of memory and
  // do not have a good way to report this on the child's side.
  std::string error_msg;
  std::unique_ptr<JNIEnvExt> child_jni_env_ext(
      JNIEnvExt::Create(child_thread, Runtime::Current()->GetJavaVM(), &error_msg));

  int pthread_create_result = 0;
  if (child_jni_env_ext.get() != nullptr) {
    pthread_t new_pthread;
    pthread_attr_t attr;
    child_thread->tlsPtr_.tmp_jni_env = child_jni_env_ext.get();
    CHECK_PTHREAD_CALL(pthread_attr_init, (&attr), "new thread");
    CHECK_PTHREAD_CALL(pthread_attr_setdetachstate, (&attr, PTHREAD_CREATE_DETACHED),
                       "PTHREAD_CREATE_DETACHED");
    CHECK_PTHREAD_CALL(pthread_attr_setstacksize, (&attr, stack_size), stack_size);
    // 调用pthread_create(UNIX环境创建线程的函数)创建一个线程
    pthread_create_result = pthread_create(&new_pthread,
                                           &attr,
                                           Thread::CreateCallback,// java Thread中的run方法在这里被调用
                                           child_thread);
    CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attr), "new thread");

    if (pthread_create_result == 0) {
      // pthread_create started the new thread. The child is now responsible for managing the
      // JNIEnvExt we created.
      // Note: we can't check for tmp_jni_env == nullptr, as that would require synchronization
      //       between the threads.
      child_jni_env_ext.release();
      return;
    }
  }

  // Either JNIEnvExt::Create or pthread_create(3) failed, so clean up.
  {
    MutexLock mu(self, *Locks::runtime_shutdown_lock_);
    runtime->EndThreadBirth();
  }
  // Manually delete the global reference since Thread::Init will not have been run.
  env->DeleteGlobalRef(child_thread->tlsPtr_.jpeer);
  child_thread->tlsPtr_.jpeer = nullptr;
  delete child_thread;
  child_thread = nullptr;
  // TODO: remove from thread group?
  env->SetLongField(java_peer, WellKnownClasses::java_lang_Thread_nativePeer, 0);
  {
    std::string msg(child_jni_env_ext.get() == nullptr ?
        StringPrintf("Could not allocate JNI Env: %s", error_msg.c_str()) :
        StringPrintf("pthread_create (%s stack) failed: %s",
                                 PrettySize(stack_size).c_str(), strerror(pthread_create_result)));
    ScopedObjectAccess soa(env);
    soa.Self()->ThrowOutOfMemoryError(msg.c_str());
  }
}

pthread_create 

以下内容来自:blog.csdn.net/mijichui215…

1. pthread_create是UNIX环境创建线程的函数
2. 头文件:#include <pthread.h>
3. 函数声明:

int pthread_create(pthread_t* restrict tidp,const pthread_attr_t* restrict_attr,void* (*start_rtn)(void*),void *restrict arg);

4. 输入参数:

tidp:事先创建好的pthread_t类型的参数。成功时tidp指向的内存单元被设置为新创建线程的线程ID。
attr:用于定制各种不同的线程属性。APUE的12.3节讨论了线程属性。通常直接设为NULL。
start_rtn:新创建线程从此函数开始运行。无参数是arg设为NULL即可。
arg:start_rtn函数的参数。无参数时设为NULL即可。有参数时输入参数的地址。当多于一个参数时应当使用结构体传入。\

5. 返回值:成功返回0,否则返回错误码。

CreateCallback    

CreateCallback 位于/art/runtime/thread.cc,代码如下:

void* Thread::CreateCallback(void* arg) {
  Thread* self = reinterpret_cast<Thread*>(arg);
  Runtime* runtime = Runtime::Current();
  if (runtime == nullptr) {
    LOG(ERROR) << "Thread attaching to non-existent runtime: " << *self;
    return nullptr;
  }
  {
    // TODO: pass self to MutexLock - requires self to equal Thread::Current(), which is only true
    //       after self->Init().
    MutexLock mu(nullptr, *Locks::runtime_shutdown_lock_);
    // Check that if we got here we cannot be shutting down (as shutdown should never have started
    // while threads are being born).
    CHECK(!runtime->IsShuttingDownLocked());
    // Note: given that the JNIEnv is created in the parent thread, the only failure point here is
    //       a mess in InitStackHwm. We do not have a reasonable way to recover from that, so abort
    //       the runtime in such a case. In case this ever changes, we need to make sure here to
    //       delete the tmp_jni_env, as we own it at this point.
    CHECK(self->Init(runtime->GetThreadList(), runtime->GetJavaVM(), self->tlsPtr_.tmp_jni_env));
    self->tlsPtr_.tmp_jni_env = nullptr;
    Runtime::Current()->EndThreadBirth();
  }
  {
    ScopedObjectAccess soa(self);
    self->InitStringEntryPoints();

    // Copy peer into self, deleting global reference when done.
    CHECK(self->tlsPtr_.jpeer != nullptr);
    self->tlsPtr_.opeer = soa.Decode<mirror::Object>(self->tlsPtr_.jpeer).Ptr();
    self->GetJniEnv()->DeleteGlobalRef(self->tlsPtr_.jpeer);
    self->tlsPtr_.jpeer = nullptr;
    self->SetThreadName(self->GetThreadName()->ToModifiedUtf8().c_str());

    ArtField* priorityField = jni::DecodeArtField(WellKnownClasses::java_lang_Thread_priority);
    self->SetNativePriority(priorityField->GetInt(self->tlsPtr_.opeer));

    runtime->GetRuntimeCallbacks()->ThreadStart(self);

    // 调用java.lang.Thread的'run'方法。
    ObjPtr<mirror::Object> receiver = self->tlsPtr_.opeer;
    jmethodID mid = WellKnownClasses::java_lang_Thread_run;
    ScopedLocalRef<jobject> ref(soa.Env(), soa.AddLocalReference<jobject>(receiver));
    InvokeVirtualOrInterfaceWithJValues(soa, ref.get(), mid, nullptr);
  }
  // Detach and delete self.
  Runtime::Current()->GetThreadList()->Unregister(self);

  return nullptr;
}

小结:
Thread.start()依次调用:
1. java_lang_Thread.cc -> nativeCreate : 判断当前线程是否可以创建线程。
2. thread.cc -> CreateNativeThread : 创建一个C的Thread对象,并将对应的java的Thread对象保活。
3. pthread_create创建一个线程
4. thread.cc -> CreateCallback :调用java.lang.Thread的'run'方法