将类声明为 Thread 的子类是创建线程的方式之一,如果我们想要在线程内定义任务那么就要重写Thread 中的run() 方法。start() 方法使我们定义的线程执行,我们已经将线程的任务定义在了run() 方法中为什么run() 方法不是执行线程的方法而是start() 方法呢?当时学线程的时候并没有多考虑这个问题,由于以前有一些误解,现在就写出来供自己与大家参考。

我定义了一个Thread 的子类ThreadTest ,在该子类中重写了run() 方法,在run() 方法中用于输出当前正在执行的线程引用,为了达到效果我让线程等待了100ms。在创建两个线程对象thread1 与thread2 后直接调用了它们的run() 方法,我们希望得到的结果是thread1 与thread2 共同抢占CPU 以达到交错输出,但是从输出的结果看出在执行的始终是主线程(main)。

public class ThreadTest  extends Thread{@Overridepublic void run() {for(int i = 0; i < 5; i++){try {Thread.sleep(100);//Thread.currentThread() 返回对当前正在执行的线程对象的引用System.out.println(Thread.currentThread());} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) {TestThread thread1 = new TestThread();TestThread thread2 = new TestThread();thread1.run();thread2.run();}
}

输出:
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]

下面我们用和上面同样的代码,不再调用ThreadTest 的run() 方法,这次调用start() 方法,看看输出结果会是什么?从下面的结果可以看出这次输出的不再是主线程,而是线程0与线程1 (但是执行的线程也包括主线程)。

public class ThreadTest extends Thread{@Overridepublic void run() {for(int i = 0; i < 3; i++){try {Thread.sleep(100);//Thread.currentThread() 返回对当前正在执行的线程对象的引用System.out.println(Thread.currentThread());} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) {TestThread thread1 = new TestThread();TestThread thread2 = new TestThread();thread1.start();thread2.start();}
}

输出
Thread[Thread-1,5,main]
Thread[Thread-0,5,main]
Thread[Thread-0,5,main]
Thread[Thread-1,5,main]
Thread[Thread-1,5,main]
Thread[Thread-0,5,main]

通过执行run() 方法与start() 方法可以知道Thread 并不是通过run() 方法执行线程的而是通过start() 方法执行线程,我们只是把线程的任务定义在了run() 方法中,但是它并不是执行任务的方法。我们知道创建执行线程任务还有一种方式,就是实现Runnable 接口。下面我们就来看一下Runnable 中的run() 方法,为了更好的对比我在run() 方法中定义了和上面一样的任务。通过上面的了解我们知道执行run() 方法并不能让线程执行,所以输出的仍然是主线程的引用。

public class RunnableTest implements Runnable {@Overridepublic void run() {for(int i = 0; i < 3; i++){try {Thread.sleep(100);System.out.println(Thread.currentThread());} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) {RunnableTest runnableTest1 = new RunnableTest();RunnableTest runnableTest2 = new RunnableTest();runnableTest1.run();runnableTest2.run();}
}

输出
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]
Thread[main,5,main]

通过看Runnable 接口的源码你就会知道这个接口只定义了一个run() 方法,这也说明着Runnable 并不能创建线程实例,那么怎么执行在其中定义的任务呢?想要创建线程实例还不简单吗,直接new 一个Thread 对象不就好了吗。Thread类 提供了一个 Thread(Runnable target) 构造器,它允许我们传入一个Runnable 子类的实例,下面我们就来这么做。

@FunctionalInterface
public interface Runnable {/*** When an object implementing interface <code>Runnable</code> is used* to create a thread, starting the thread causes the object's* <code>run</code> method to be called in that separately executing* thread.* <p>* The general contract of the method <code>run</code> is that it may* take any action whatsoever.** @see     java.lang.Thread#run()*/public abstract void run();
}

重新定义了两个Thread 类实例并将RunnableTest 对象传入Thread 类中的构造器,然后由线程实例thread1 与thread2 执行线程任务,我们看到正如我们所希望的那样打印着执行线程的引用。

public class RunnableTest implements Runnable {@Overridepublic void run() {for(int i = 0; i < 3; i++){try {Thread.sleep(100);System.out.println(Thread.currentThread());} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) {RunnableTest runnableTest1 = new RunnableTest();RunnableTest runnableTest2 = new RunnableTest();Thread thread1 = new Thread(runnableTest1);Thread thread2 = new Thread(runnableTest2);thread1.start();thread2.start();}
}

输出
Thread[Thread-1,5,main]
Thread[Thread-0,5,main]
Thread[Thread-1,5,main]
Thread[Thread-0,5,main]
Thread[Thread-1,5,main]
Thread[Thread-0,5,main]

总结:
      Thread 中的run() 方法只是定义了线程的任务但是它不负责执行该任务,如果你调用该方法那么执行的只是主线程,就像某一个对象实例调用它自己的方法一样。
      Thread 中的start() 方法才是执行线程的方法,在执行该方法时,Java 虚拟机会调用该线程的run() 方法,从而达到并发执行的目的。在这里你需要注意的是多次启动一个线程是不安全的,特别是线程执行结束后,不要再重新启动,这点要特别注意。
      在这里也通过实现Runnable 接口来定义线程任务,需要注意的是Runnable 接口的实现并不能创建线程实例,当你想要执行其中定义的任务时,你需要将该子类的实例作为参数传入Thread 中的构造器,通过Thread 类的实例来执行线程任务。

Thread 中的run() 与start() 方法相关推荐

  1. 1)编写Animal接口,接口中声明run()方法; 2)定义Bird类和Fish类实现Animal接口; 3)编写Bird类和Fish类的测试程序,并调用其中的run()方法

    /*1)编写Animal接口,接口中声明run()方法:   2)定义Bird类和Fish类实现Animal接口:   3)编写Bird类和Fish类的测试程序,并调用其中的run()方法 */ in ...

  2. IntelliJ Idea学习笔记003---IDEA中打开Run DashBoard的方法

    技术交流QQ群[JAVA,C++,Python,.NET,BigData,AI]:170933152 微服务项目的开发过程中,工程会非常多,经常要启动很多个服务,才能完成一项测试.启动的多了,容易开发 ...

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

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

  4. run()和start()方法区别

    多线程原理:相当于玩游戏机,只有一个游戏机(cpu),可是有很多人要玩,于是,start是排队!等CPU选中你就是轮到你,你就run(),当CPU的运行的时间片执行完,这个线程就继续排队,等待下一次的 ...

  5. Hystrix的一个坑,queue中的run方法没有被执行?

    今天学的时候随手测了一下Hystrix的queue的异步执行,发现执行queue之后,还没有打印run方法中的内容,程序就结束了: import com.netflix.hystrix.Hystrix ...

  6. 线程的常用方法——currentThread方法||在main方法中直接调用run()方法,没有开启新的线程,以在run方法中的当前线程就是main线程||启动子线程,子线程会调用run方法

    线程的常用方法--currentThread方法 Thread.currentThread()方法可以获得当前线程 Java 中的任何一段代码都是执行在某个线程当中的. 执行当前代码的线程就是当前线程 ...

  7. 多线程中 start()和run()方法的区别

    多线程中  start()和run()方法的区别: Java线程一直是一个比较容易困扰的地方,首先,我们来认识下怎样生存线程. 认识 Thread 和Runnable java中实现多线程有两种途径: ...

  8. [面试] Thread 中 start() 和 run() 的区别都不知道,还怎么混?

    引子 最近面试了不少 Java 工程师,有一些心得体会想给大家分享,比如,上次就有一个小哥被我 "送走" 了,我尽量复原一下当时的面试情景,对话大致如下: 我:我们知道,JDK 中 ...

  9. 创建两个Thread子类,第一个用run()方法启动,并捕获第二个Thread对象的句柄,然后调用wait()。第二个类的run()方法几秒后为第一个线程调用notifAll(),使第一个线程打印消息

    创建两个Thread子类,第一个用run()方法启动,并捕获第二个Thread对象的句柄,然后调用wait().第二个类的run()方法几秒后为第一个线程调用notifAll(),使第一个线程打印消息 ...

最新文章

  1. 【GDOI2014模拟】旅行 题解代码
  2. 【身份认证及权限控制一】单点登录
  3. c语言程序年月日怎么编,C语言程序设计: 输入年月日 然后输出是星期几
  4. 50阶乘c语言思想,求10000的阶乘(c语言代码实现)
  5. C# WinForm禁止改变大小 最大化最小化隐藏 最大化最小化隐藏
  6. Mac里的airdrop传输文件
  7. Learning Premiere Elements 15 Premiere Elements 15教程 Lynda课程中文字幕
  8. iphone6连接电脑后计算机不显示器,苹果手机怎么连接电脑没反应
  9. 内网安全检测技术yyds!你还不会吗?
  10. 加拿大留学有何魅力,可以吸引众留学生蜂拥而至
  11. ZCANPRO 周立功CAN通道配置方法
  12. NR-PRACH:接入场景和接入流程
  13. 2023 iApp 图片漫画化源码
  14. C语言%7.2d、%-7d、%7.2f、%0.2f的含义和区别
  15. [PyQt5]基本控件19 - 分割条QSplitter
  16. Kafka SASL/SCRAM动态认证集群部署
  17. 12306订票助手 (版本 3.5.0)
  18. 8月12日科技资讯|今日头条搜索网页版上线;华为筹建中国开源基金;Racket v7.4 发布
  19. Python学习笔记D3(列表与元组)
  20. 现代数学发展的大趋势

热门文章

  1. Linux下安装部署ElasticSearch教程【7.10.1】
  2. 手把手带你领略双十一背后的核心技术Sentinel之热点参数限流
  3. 前端如何让倒计时更准确
  4. idea中启动RunDashboard
  5. Zero Quantity Maximization
  6. android gradle自定义钉钉群提醒
  7. Android JNI 和 NDK
  8. Android 首页图片轮播
  9. Java 装饰器模式详解
  10. 源码学习【HashMap第一篇】HashMap到底是怎么put的?