Thread中的start和run方法的区别

面试必问,面试必问,面试必问!别问我为什么知道~~

总结

  • run()只是Thread类的一个普通方法,调用run()并不会新建一个子线程,仍在主线程执行任务。
  • 调用start()会新建一个子线程并执行run()的内容。调用start()会有两个线程,一个是当前正在调用start()的主线程;另一个是JVM创建的子线程,用来执行run()的内容。

实践

实践出真知~~首先写下测试代码:

public class ThreadTest {

    static void printThreadName(){
        System.out.println("printThreadName: "+Thread.currentThread().getName());
    }

    public static void main(String[] args) {

        // 也可用lambda表达式替换,更简洁:new Thread(() -> printThreadName());
        Thread thread = new Thread(){
            @Override
            public void run() {
                printThreadName();
            }
        };

        System.out.println("main thread name: "+Thread.currentThread().getName());
        thread.run();
    }
}

打印结果:

main thread name: main
printThreadName: main

说明使用run()方法并未另起一个线程执行,而是使用主线程执行。run()方法只是Thread的一个普通方法。

我们将上面代码中的run()方法换成start()试试看。

public class ThreadTest {

    static void printThreadName(){
        System.out.println("printThreadName: "+Thread.currentThread().getName());
    }

    public static void main(String[] args) {

        // 也可用lambda表达式替换,更简洁:new Thread(() -> printThreadName());
        Thread thread = new Thread(){
            @Override
            public void run() {
                printThreadName();
            }
        };

        System.out.println("main thread name: "+Thread.currentThread().getName());
        thread.start();

    }
}

打印结果:

main thread name: main
printThreadName: Thread-0

发现调用start()方法会新建一个子线程执行run()方法的内容。为什么呢?下面深入源码:

 /**
     * JVM会调用该线程的run()方法去执行。
     * 
     * 执行该方法会有两个线程:一个是当前线程,用来执行start()方法;另一个线程去执行它的run()方法。
     * 
     * start()只能被调用一次,否则会提示IllegalThreadStateException
     *
     */
public synchronized void start() {
        /**
         * 0 表示新建状态
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
       //忽略不重要的代码
      .....
        try {
           
            start0();
        } finally {
           ....
    }

    //本地方法:说明不是用java写的
    private native void start0();

查看源码,发现start()最终调用start0(),start0()是一个native方法,要看这块代码做了什么,我们可以到这个网站去查询(jdk8u-thread.c)。
发现该方法调用了JVM去启动一个新线程。

 {"start0",           "()V",        (void *)&JVM_StartThread},

通过同个网站(jdk-jvm)查看对应的JVM_StartThread源码。

// 新建了一个线程
 native_thread = new JavaThread(&thread_entry, sz);
// 调用了该线程的run()方法。
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);
}

就此结束啦~

看懂的朋友可以再做下练习题,最后打印什么?“pingpong"还是”pongping",还是都有可能呢?

public class ThreadTest {

    static void printThreadName(){
        System.out.println("ping");
    }

    public static void main(String[] args) {

        // 用lambda表达式替换,更简洁:
        new Thread(() -> printThreadName()).run();
        System.out.println("pong");
    }
}
  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值