为什么使用start方法启动Java的Thread线程?
一、簡介
在Java代碼當(dāng)中,當(dāng)我們需要開啟子線程去處理一些任務(wù)的時候,往往是調(diào)用Thread對象的start方法,這樣Thread實例中的Runnable對象的run方法就會在一個新的線程當(dāng)中執(zhí)行;
// 創(chuàng)建一個線程 Thread thread = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("working in " + Thread.currentThread().getName());} });// 在什么線程調(diào)用,run方法的任務(wù)就在什么線程執(zhí)行 thread.run();// 在一個新的線程中執(zhí)行run方法中的任務(wù) thread.start();二、分析run()方法
如下代碼可見,當(dāng)我們直接調(diào)用run方法的時候,就相當(dāng)于實例直接調(diào)用一個普通的方法一樣,所以無論我們在什么線程中調(diào)用run方法,run方法中的業(yè)務(wù)就在什么線程執(zhí)行,并不會說啟動一個新的線程去執(zhí)行run方法中的任務(wù);
// Thread.class中的run方法,target為Runnable實例 @Override public void run() {if (target != null) {target.run();} }三、分析start()方法
如下我們直接來看Thread.class中的代碼;
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. */// 1. 將當(dāng)前線程實例添加到ThreadGroup對象group中group.add(this);boolean started = false;try {// 2. 調(diào)用native方法start0()start0();started = true;} finally {try {if (!started) {group.threadStartFailed(this);}} catch (Throwable ignore) {/* do nothing. If start0 threw a Throwable thenit will be passed up the call stack */}} }// native 方法 private native void start0();看上面代碼的注釋1那里,我們來看下Thread.class代碼里面group是哪里來的
private void init(ThreadGroup g, Runnable target, String name,long stackSize, AccessControlContext acc,boolean inheritThreadLocals) {if (name == null) {throw new NullPointerException("name cannot be null");}this.name = name;Thread parent = currentThread();// 1. 從System類中獲取安全管理器SecurityManager security = System.getSecurityManager();if (g == null) {/* Determine if it's an applet or not *//* If there is a security manager, ask the security managerwhat to do. */if (security != null) {// 2. 從安全管理器中過去ThreadGroup對象g = security.getThreadGroup();}/* If the security doesn't have a strong opinion of the matteruse the parent thread group. */if (g == null) {g = parent.getThreadGroup();}}g.addUnstarted();this.group = g;// 省略一部分代碼··· }從上面注釋1,2可以看出,Thread實例中的ThreadGroup實例g主要是從底層代碼中獲取的,即group.add(this)執(zhí)行之后,將當(dāng)前線程傳給了底層系統(tǒng)去管理
下面看下start0()方法,因為start0()方法為Native方法,看下是怎么實現(xiàn)的,如下為src/main/native/Thread.c的代碼
static JNINativeMethod methods[] = {// 從這里我們可以看到start0方法主要JVM_StartThread的一個方法引用{"start0", "(JZ)V", (void *)&JVM_StartThread},{"setPriority0", "(I)V", (void *)&JVM_SetThreadPriority},{"yield", "()V", (void *)&JVM_Yield},{"sleep", "(Ljava/lang/Object;J)V", (void *)&JVM_Sleep},{"currentThread", "()" THD, (void *)&JVM_CurrentThread},{"interrupt0", "()V", (void *)&JVM_Interrupt},{"isInterrupted", "(Z)Z", (void *)&JVM_IsInterrupted},{"holdsLock", "(" OBJ ")Z", (void *)&JVM_HoldsLock},{"setNativeName", "(" STR ")V", (void *)&JVM_SetNativeThreadName}, };下面一下JVM_StartThread的情況
// 如下為/openjdkjvm/OpenjdkJvm.cc中的代碼 JNIEXPORT void JVM_StartThread(JNIEnv* env, jobject jthread, jlong stack_size, jboolean daemon) {art::Thread::CreateNativeThread(env, jthread, stack_size, daemon == JNI_TRUE); }// 如下為/runtime/thread.cc中創(chuàng)建native線程的代碼 void Thread::CreateNativeThread(JNIEnv* env, jobject java_peer, size_t stack_size, bool is_daemon) {···// 這里就不做展開了 }總結(jié):從上面代碼可以看出,Thread調(diào)用start的時候,將thread實例傳給虛擬機持有,然后調(diào)用native創(chuàng)建一個新的線程,由虛擬機進行調(diào)度。
水平有限,有誤請指正!
總結(jié)
以上是生活随笔為你收集整理的为什么使用start方法启动Java的Thread线程?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何用python做比分网_python
- 下一篇: NFT 数字藏品 3D 展示方案(obj