• Thread类中run和start的区别


    一.认识 Thread类 中的 start() 和 run()

    首先来看一张jdk-api中对于start 和 run 的描述.

     

    二.方法的区别

     下面我们简单看一下代码:

    1. // 继承Thread类 重写run()
    2. class MyThread extends Thread {
    3. @Override
    4. public void run() {
    5. while (true) {
    6. System.out.println("thread");
    7. try {
    8. sleep(1000);
    9. } catch (InterruptedException e) {
    10. e.printStackTrace();
    11. }
    12. }
    13. }
    14. }
    15. public class Demo1 {
    16. public static void main(String[] args) {
    17. MyThread thread = new MyThread();
    18. thread.start();
    19. while (true) {
    20. System.out.println("main");
    21. try {
    22. Thread.sleep(1000);
    23. } catch (InterruptedException e) {
    24. e.printStackTrace();
    25. }
    26. }
    27. }
    28. }
    1. // 通过重写Runnable 来实现创建线程
    2. class MyRunnable implements Runnable {
    3. @Override
    4. public void run() {
    5. while (true) {
    6. System.out.println("thread");
    7. try {
    8. Thread.sleep(1000);
    9. } catch (InterruptedException e) {
    10. e.printStackTrace();
    11. }
    12. }
    13. }
    14. }
    15. public class Demo2 {
    16. public static void main(String[] args) {
    17. MyRunnable runnable = new MyRunnable();
    18. Thread thread = new Thread();
    19. thread.start();
    20. while (true) {
    21. System.out.println("main");
    22. try {
    23. Thread.sleep(1000);
    24. } catch (InterruptedException e) {
    25. e.printStackTrace();
    26. }
    27. }
    28. }
    29. }

    通过上述代码, 我们可以看出, 无论哪一种方法创建线程, 我们都需要重写run(), 而API中对于run() 的介绍,如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。Thread 的子类应该重写该方法。run()方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。

    我们确定一件事, start() 才是真正启动线程的方法, 真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。

    通过调用Thread类的start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行, 然后通过此Thread类调用方法run()来完成其运行操作的, 这里方法run()称为线程体,它包含了要执行的这个线程的内容Run方法运行结束, 此线程终止。然后CPU再调度其它线程。 一旦得到cpu时间片,就开始执行run()方法,这里方法 run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止

    三.运行结果的区别

    图一, 继承Thread类打印效果

    这个时候创建了新的线程, 打印了 thread

    然后, 操作系统, 调度线程的时候, 是一个 "随机" 的过程

    执行 sleep, 线程就进入阻塞.

    sleep 时间一到, 线程就恢复就绪状态, 参与线程调度.

    当两个线程都参与调度的时候, 不确定谁先谁后

     图二, 重写Runnable接口

    这个时候只是打印了 main , 并没有创建新的线程

    实现Runnable接口,创建Thread时,会调用

    1. public Thread(Runnable target) {
    2. init(null, target, "Thread-" + nextThreadNum(), 0);
    3. }
    4. private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
    5. init(g, target, name, stackSize, null, true);
    6. }

    把Runnable的实现类赋值给target,当使用run方法时```java会调用我们实现时写的run()方法. 因此,run方法只是调用了一个普通方法,并没有启动另一个线程,程序还是会按照顺序执行相应的代码, 因此,无论使用哪种方式创建线程, run方法都是用来处理线程对应的业务逻辑. 

  • 相关阅读:
    第二证券:机构策略:大盘有望继续走出震荡攀升走势
    无名管道与有名管道(FIFO)的应用
    IDEA常用快捷键总结(Windows)
    MIPS汇编语言学习-01-两数求和以及环境配置、如何运行
    基本排序算法的总结笔记
    注册 ,登录, 注销功能实现 springBoot集成redis实现token ——yml配置逻辑删除
    纯CSS制作3D动态相册【流星雨3D旋转相册】HTML+CSS+JavaScriptHTML5七夕情人节表白网页制作
    深入理解Spring Boot AOP:CGLIB代理与JDK动态代理的完全指南
    SpringMvc-HttpMessageConverter接口
    Gin 笔记(04)— 自定义 HTTP 配置、使用 HTTP 方法、自定义请求 url 不存在时的返回值、自定义重定向
  • 原文地址:https://blog.csdn.net/qq_52592775/article/details/127699734