Thread -- 05 -- start()与run()的区别

原文链接:Thread – 05 – start()与run()的区别


相关文章:


在平常使用线程的过程中,我们可定会有这么一个疑问,启用线程时使用 start() 方法而不是 run() 方法,这两个方法之间究竟有什么区别呢,这里让我们来一起深入了解下


一、举例说明

  • 例子一 (调用 run() 方法)

    public class CurrentThreadTest {
    
        private static void attack() {
            System.out.println("Fight");
            System.out.println("Current Thread is: " + Thread.currentThread().getName());
        }
    
        public static void main(String[] args) {
            Thread thread = new Thread() {
                @Override
                public void run() {
                    attack();
                }
            };
            System.out.println("Current Thread is: " + Thread.currentThread().getName());
            thread.run();
        }
    }
    
    // Current Thread is: main
    // Fight
    // Current Thread is: main
    
    • 如上所示,我们定义了一个 attack(),并打印出执行该方法的线程名称,另外在 main() 方法中 new 了一个线程,打印出执行 main() 方法的线程名称,并调用 run() 方法

    • 由输出可知,执行 main() 方法和 attack() 方法的为同一个线程,即主线程 main


  • 例子二 (调用 start() 方法)

    public class CurrentThreadTest {
    
        private static void attack() {
            System.out.println("Fight");
            System.out.println("Current Thread is: " + Thread.currentThread().getName());
        }
    
        public static void main(String[] args) {
            Thread thread = new Thread() {
                @Override
                public void run() {
                    attack();
                }
            };
            System.out.println("Current Thread is: " + Thread.currentThread().getName());
            thread.start();
        }
    }
    
    // Current Thread is: main
    // Fight
    // Current Thread is: Thread-0
    
    • 如上所示,调用了线程的 start() 方法,由输出可知,执行 main() 方法和 attack() 方法的不是同一个线程,也就是说当调用 start() 时,会创建一个新的线程来调用 attack() 方法

二、源码解析

  • start()

    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();
    
    • 源码如上,可知 start() 方法中主要调用的方法为 start0() 方法,这是一个本地方法,我们可以通过 openjdk 来查看其源码 (该方法位于 Thread.c 类下)
  • Thread.c --> 传送门

    #include "jni.h"
    #include "jvm.h"
    
    #include "java_lang_Thread.h"
    
    #define THD "Ljava/lang/Thread;"
    #define OBJ "Ljava/lang/Object;"
    #define STE "Ljava/lang/StackTraceElement;"
    #define STR "Ljava/lang/String;"
    
    #define ARRAY_LENGTH(a) (sizeof(a)/sizeof(a[0]))
    
    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 的源码
  • jvm.cpp --> 传送门

    jlong size =
    java_lang_Thread::stackSize(JNIHandles::resolve_non_null(jthread));
    // Allocate the C++ Thread structure and create the native thread.  The
    // stack size retrieved from java is signed, but the constructor takes
    // size_t (an unsigned type), so avoid passing negative values which would
    // result in really large stacks.
    size_t sz = size > 0 ? (size_t) size : 0;
    native_thread = new JavaThread(&thread_entry, sz);
    
    
    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);
    }
    
    • 源码如上,可知 JVM_StartThread() 方法中 new 了一个 Java 线程,该方法其中一个参数方法: thread_entry(),在 thread_entry() 方法中,会调用虚拟机并传入 run() 方法的名字

    • 也就是说,最终 new 了一个线程,然后用这个线程去执行 run() 方法里面的内容

    在这里插入图片描述


三、归纳总结

  • 调用 start() 方法会创建一个新的子线程并启动

  • 调用 run() 方法只不过是调用了 Thread 类的一个普通方法

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值