由于Java是支持单继承的(接口除外),所以我们普遍启动线程的方式都是实现Runnable接口并重写run()方法。先来看下面一个简单的实例:

public class MyRunnable implements Runnable { @Override public void run() { try { // 睡眠3秒 TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("实现Runnable接口的线程"); }}

public class MyRunnableTest { public static void main(String[] args) throws InterruptedException { System.out.println("--------开始调用线程--------"); Thread thread= new Thread(new MyRunnable()); thread.run(); System.out.println("--------调用线程结束--------");    }}

你能猜出上面执行的顺序吗?或许你可以试着尝试用机器运行一下,把得到的结果和你的猜想进行一个验证。

运行之前请仔细思考一下,如果run()方法启动了一个线程的话,那么在“MyRunnable”中我们设置了休眠,主线程应该继续往下执行,那么输出的结果应该就是:

--------开始调用线程----------------调用线程结束--------实现Runnable接口的线程


但是,我们来看下实际的运行结果:

--------开始调用线程--------实现Runnable接口的线程--------调用线程结束--------

很显然run()方法其实是按照顺序执行的,并没有真正的启动一个线程。在解释原因之前我们先来看看下面这段代码:

Thread thread= new Thread(new MyRunnable());

这段代码也就是构造了一个thread对象,并且把我们实现的Runnable传递了进去。我们点进源码查看一下这个构造方法。

public Thread(Runnable target) { init(null, target, "Thread-" + nextThreadNum(), 0);}

在这里,先不需要了解构造方法的每一参数,只需要注意一下我们传递进来的“MyRunnable”它是一个Runnable对象,这里赋给了"target"。请先记住这一点,他在后面的解析中很重要。

重点来了:接下来我们再来看看所谓的线程启动的代码:

thread.run();

我们还是点击进去源码,能看到如下的代码示例:

@Overridepublic void run() { if (target != null) { target.run(); }}

我想看到“@Override”这个关键词,大家应该立刻想到他是一个方法的重写,然后我们发现,其实Thread类也是实现了“Runnable”接口的。这里看到“target ”其实就是我们自定义的MyRunnable,“target.run()”最终调用的方法也就是“MyRunnable.run()”。因此可以得出一个结论,run()方法并不会真正的启动一个线程,调用run()方法,就相当于调用了一个普通方法,程序还是按照顺序执行的。下图展示了调用的过程。

然后我们尝试正确的启动一个线程,代码如下:

public class MyRunnableTest { public static void main(String[] args) throws InterruptedException { System.out.println("--------开始调用线程--------"); Thread thread= new Thread(new MyRunnable()); thread.start(); System.out.println("--------调用线程结束--------"); }}

运行结果:

--------开始调用线程----------------调用线程结束--------实现Runnable接口的线程

通过运行程序可以发现,这次的输入内容是符合我们之前的预期的。我们再次点进“start()”的源码进行查看(不用每一行都了解其原理,先大致了解即可。):

public synchronized void start() {           if (threadStatus != 0) throw new IllegalThreadStateException();      group.add(this);      boolean started = false;      try {          start0();          started = true;      } finally {          try {              if (!started) {                  group.threadStartFailed(this);              }            } catch (Throwable ignore) {          }      }  }

这里比较重要的一个方法就是“start0()”跟进“start0()”的源码能够发现这个方法调用的是一个本地的方法,也就是交给底层去实现了。

private native void start0();

Thread.start()--->start0()--->run()

总的来说我们启动一个线程的话,构造好线程之后,调用“start()”方法才算真正的启动了一个线程。

qthread run结束了算销毁吗_Java线程的run()方法和start()方法有什么区别?相关推荐

  1. qthread run结束了算销毁吗_对 精致码农大佬 说的 Task.Run 会存在 内存泄漏 的思考...

    一:背景 1. 讲故事 这段时间项目延期,加班比较厉害,博客就稍微停了停,不过还是得持续的技术输出呀! 园子里最近挺热闹的,精致码农大佬分享了三篇文章: 为什么要小心使用 Task.Run [http ...

  2. qthread run结束了算销毁吗_拼多多,一面,i++ 是线程安全的吗?一脸蒙逼!

    i++ 是线程安全的吗? 相信很多中高级的 Java 面试者都遇到过这个问题,很多对这个不是很清楚的肯定是一脸蒙逼.内心肯定还在质疑,i++ 居然还有线程安全问题?只能说自己了解的不够多,自己的水平有 ...

  3. qthread run结束了算销毁吗_会计职称考试已结束,证书怎么领?

    2020年会计职称考试已结束,坐等领证书! 那么,问题来了?证书什么时候可以领?需要准备什么资料?证书长啥样?通过考试了还需要继续教育吗? 会计职称证书什么时候领? 01 2020年初级.中级会计查分 ...

  4. Thread类的run方法和start方法

    Thread类的run方法和start方法 start方法是Thread类中的方法,用于启动新的线程.而调用run方法时,不会启动新的线程.在调用start方法后,程序会在后台启动新的线程.然后,由这 ...

  5. 线程run方法和start方法的区别

    区别 run() 只是一个普通的方法调用,不会开启新的线程. start() 会开启新的线程,分配新的资源.里面的变量互不影响. 实例 package multithreading;public cl ...

  6. java run() 返回值_java线程的run()没有返回值怎么办?

    用线程Thread执行一些方法后,需要判断执行是否成功. public void run() {} run( ) 方法返回值是空, 怎么办? 解决方法: Note 使用 call() 方法 Calla ...

  7. java heap 参数_java heap space解决方法和JVM参数设置

    因为程序要从数据读取近10W行记录处理,当读到9W的时候就出现 java.lang.OutOfMemoryError: Java heap space 这样的错误. 在网上一查可能是JAVA的堆栈设置 ...

  8. java heap space 什么意思_java heap space解决方法和JVM参数设置

    因为程序要从数据读取近10W行记录处理,当读到9W的时候就出现 java.lang.OutOfMemoryError: Java heap space 这样的错误. 在网上一查可能是JAVA的堆栈设置 ...

  9. run()方法和start()方法测试解析

    run()方法没有启动一个新的线程,通过如下代码可以看出,是main主线程执行的 start()方法启动了一个新线程,启动了线程,从如下代码看出t1线程执行了代码

最新文章

  1. 我的微软最有价值专家(Microsoft MVP)之路
  2. 获取收藏夹路径的C++代码
  3. ML之sklearn:sklearn.metrics中常用的函数参数(比如confusion_matrix等 )解释及其用法说明之详细攻略
  4. 细品慢酌QuickTest关键视图(5)脚本调试
  5. 洛谷——P1640 [SCOI2010]连续攻击游戏
  6. 实现将字符串转换为指令执行
  7. 为什么苹果不再需要谷歌地图?
  8. python集合set,frozenset--笔记
  9. 设置线程当天十二点执行_这份JAVA多线程笔记真的是细节满满,几乎全是你工作能用到的干货...
  10. SecureDrop 0.3,LibreOffice Online和更多新闻
  11. Python3数据结构总结(列表list,元组tuple,集合set,字典dict,堆栈stack,队列queue和遍历技巧)
  12. 蓝桥杯 ALGO-115 算法训练 和为T
  13. 201542010208、201571030331软件工程结对项目
  14. phpstudy之解决phpmyadmin卡顿的方法
  15. pymysql数据库使用教程_小白进阶之路,如何使用pymysql直连数据库?
  16. 易筋SpringBoot 2.1 | 第十八篇:SpringBoot的JDBC异常
  17. 137、TensorFlow使用TextCNN进行文本分类
  18. 经验贴: 如何选购相机, 电脑, 手机, 电脑配件?
  19. matlab如何实现信道衰落,Matlab下多径衰落信道的仿真
  20. 写行政区划数据方案设计系列有感

热门文章

  1. 【kafka】kafka 脚本 kafka-run-class.sh 使用介绍 jmx监控 查看jmx信息
  2. 【Elasticsearch】Elasticsearch bouncing result 问题
  3. Maven : Maven和jenkins报错 ClassNotFoundException : org.slf4j.Logger
  4. 【Flink】Flink调优指南
  5. Spring : @ComponentScan注解
  6. 【hue】Bad status: 3 (PLAIN auth failed: Error validating LDAP user)
  7. 面试官:如果要存ip地址,用什么数据类型比较好?
  8. 你真的理解BIO、NIO、AIO的区别吗?
  9. Flask使用ajax进行前后端交互
  10. c语言双链表从右向左遍历,有没有大佬在的,我这双向链表怎么没办法遍历