热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

start()方法和run()方法区别与多线程抢占式运行原理

目录start()与run()方法区别多线程抢占式运行原理start()与run()方法区别我们通过一个例子来进行总结,我们写一个利用Thread创建的简单的多线程

目录

      • start()与run()方法区别
      • 多线程抢占式运行原理


start()与run()方法区别

我们通过一个例子来进行总结,我们写一个利用Thread创建的简单的多线程例子,然后分别执行start()与run()方法,执行结果如下所示:

/*** @author :zjc* @ProjectName: execises* @Package: com.execises.zjc.controller.thread* @ClassName: ThreadRunAndStartMethodCompare* @date :Created in 2021/7/17 10:20* @description:对比run()和start()方法* @modified By:* @version: v1.0.0$*/
public class ThreadRunAndStartMethodCompare extends Thread {private String name;public ThreadRunAndStartMethodCompare(String name) {this.name = name;}@Overridepublic void run() {super.run();System.out.println(name);}public static void main(String[] args) {new ThreadRunAndStartMethodCompare("唐山大兄本兄").run();//new ThreadRunAndStartMethodCompare("唐山大兄本兄").start();}}

这里先执行了start()方法
在这里插入图片描述
在执行时,我们看到新生成了一个线程,这样与主线程分离开,实现了并行执行。

start()方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码:

1、通过调用Thread类的start()方法来启动一个线程,这时此线程是处于就绪状态,并没有运行。
2、然后通过此Thread类调用方法run()来完成其运行操作,这里方法run()称为线程体,它包含了要执行的这个线程的内容。
3、run()方法运行结束,此线程终止,而CPU再运行其它线程。

执行run方法
在这里插入图片描述

run()方法在这里可以看到并没有线程产生,只有单独的主进程

只是当作普通方法的方式调用,程序还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码。在这里我们是直接用run()方法,这只是调用一个方法而已,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,这样就没有达到写线程的目的。

Thread底层也是用Runnable的run()方法来执行,其中target就是Runnable的变量名。

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

Thread对象的run()方法在一种循环下,使线程一直运行,直到不满足条件为止,在你的main()里创建并运行了一些线程,调用Thread类的start()方法将为线程执行特殊的初始化的过程,来配置线程,然后由线程执行机制调用run()方法。如果你不调用start()方法,线程就不会启动。

因为线程调度机制的行为是不确定的,所以每次运行该程序都会有不同的结果,你可以把你的循环次数增多些,然后看看执行的结果,你会发现main()的主线程和Thread子线程是交替运行的。我们看下面一段代码:

/*** @author :zjc* @ProjectName: execises* @Package: com.execises.zjc.controller.thread* @ClassName: ThreadOpByThread* @date :Created in 2021/7/16 15:03* @description:创建多线程之继承Thread类* @modified By:* @version: v1.0.0$*/
public class ThreadOpByThread extends Thread {&#64;Overridepublic void run() {super.run();for (int i &#61; 0; i < 100; i&#43;&#43;) {System.out.println(Thread.currentThread().getName() &#43; i);}}static class testThread {public static void main(String[] args) {ThreadOpByThread threadOpByThread &#61; new ThreadOpByThread();threadOpByThread.start();for (int i &#61; 0; i < 100; i&#43;&#43;) {System.out.println("我是主线程"&#43; i);}}}}

输出结果为&#xff1a;

我是主线程0
Thread-00
我是主线程1
Thread-01
Thread-02
Thread-03
Thread-04
Thread-05
我是主线程2
我是主线程3
我是主线程4
我是主线程5
我是主线程6
我是主线程7
我是主线程8
Thread-06

在执行过程中会相互并发穿插执行&#xff0c;子线程执行完毕后依然会回到主线程&#xff0c;交给主线程最终执行&#xff0c;这也就是并发执行的高效率之所在。

多线程抢占式运行原理

经过我运行下面这段代码&#xff0c;发现每次生成的线程顺序号都是会变的&#xff0c;并不是按照顺序来执行&#xff1a;

/*** &#64;author &#xff1a;zjc* &#64;ProjectName: execises* &#64;Package: com.execises.zjc.controller.thread* &#64;ClassName: ThreadRunAndStartMethodCompare* &#64;date &#xff1a;Created in 2021/7/17 10:20* &#64;description&#xff1a;对比run()和start()方法* &#64;modified By&#xff1a;* &#64;version: v1.0.0$*/
public class ThreadRunAndStartMethodCompare extends Thread {private String name;public ThreadRunAndStartMethodCompare(String name) {this.name &#61; name;}public ThreadRunAndStartMethodCompare() {}&#64;Overridepublic void run() {super.run();System.out.println(name);}public static void main(String[] args) {ThreadRunAndStartMethodCompare threadRunAndStartMethodCompare &#61; new ThreadRunAndStartMethodCompare();//new ThreadRunAndStartMethodCompare("张建超").run();for (int i &#61; 0; i < 100; i&#43;&#43;) {threadRunAndStartMethodCompare.demo(i);}}public void demo(int i) {synchronized (this) {new ThreadRunAndStartMethodCompare("唐山大兄本兄" &#43; i).start();}}}

输出结果&#xff1a;

唐山大兄本兄0
唐山大兄本兄5
唐山大兄本兄3
唐山大兄本兄2
唐山大兄本兄1
唐山大兄本兄4
唐山大兄本兄6
唐山大兄本兄7
唐山大兄本兄8
唐山大兄本兄10
唐山大兄本兄18
唐山大兄本兄12
唐山大兄本兄20
唐山大兄本兄13
唐山大兄本兄14

在这里插入图片描述
原因&#xff1a;

1、当java虚拟机&#xff08;也就是经常说的 JVM&#xff09;执行mian方法的时候&#xff0c;他会找操作系统&#xff08;也就是os&#xff09;开辟一条main方法通向cpu的路径&#xff0c;这个路径就是main线程&#xff0c;也就是所说的主线程。

2、接着cpu通过这个线程&#xff0c;也就是这个路径&#xff0c;就可以执行main方法了。

3、当我们new了一个Thread对象&#xff0c;这个时候又开辟了一条通向cpu的路径&#xff0c;而这条路径是用来执行run方法的。

4、而现在对于cpu而言&#xff0c;他就有了很多条执行的路径&#xff0c;cpu就有了选择的权利&#xff0c;cpu他喜欢谁&#xff0c;就会执行哪条路径&#xff0c;我们是控制不了cpu的&#xff0c;所有就有了出现随机打印的结果。

反过来说&#xff0c;两个线程&#xff0c;一个main线程&#xff0c;一个新线程&#xff0c;他们一起抢夺cpu的执行权&#xff08;即 cpu的执行时间&#xff09;&#xff0c;谁抢到了&#xff0c;谁先执行。

也可以这么来理解&#xff1a;

0到99这段时间太短&#xff0c;对于CPU分配给这个线程的时间片来说足够完成了&#xff0c;也就呈现出0到99个线程同时初始化&#xff0c;然后剩下的线程再争夺CPU资源&#xff0c;在我们Debug调试的时候输出就是0到99的顺序&#xff0c;不用Debug调试直接运行就不是0到99输出。大致可以理解为创建了所有的线程&#xff0c;再争用资源。调试的时候有断点&#xff0c;产生了优先级&#xff0c;所以才按序输出的。

这边发现一个讲run()和start()的比较详细的文章&#xff0c;链接地址放在这里&#xff1a;
https://blog.csdn.net/chengp919/article/details/77336328

欢迎感兴趣的小伙伴一起探讨学习知识&#xff0c;以上是个人的一些总结分享&#xff0c;如有错误的地方望各位留言指出&#xff0c;十分感谢。

觉得有用的话别忘点赞、收藏、关注&#xff0c;手留余香&#xff01; &#x1f617; &#x1f617; &#x1f617;


推荐阅读
  • 纠正网上的错误:自定义一个类叫java.lang.System/String的方法
    本文纠正了网上关于自定义一个类叫java.lang.System/String的错误答案,并详细解释了为什么这种方法是错误的。作者指出,虽然双亲委托机制确实可以阻止自定义的System类被加载,但通过自定义一个特殊的类加载器,可以绕过双亲委托机制,达到自定义System类的目的。作者呼吁读者对网上的内容持怀疑态度,并带着问题来阅读文章。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文详细介绍了在ASP.NET中获取插入记录的ID的几种方法,包括使用SCOPE_IDENTITY()和IDENT_CURRENT()函数,以及通过ExecuteReader方法执行SQL语句获取ID的步骤。同时,还提供了使用这些方法的示例代码和注意事项。对于需要获取表中最后一个插入操作所产生的ID或马上使用刚插入的新记录ID的开发者来说,本文提供了一些有用的技巧和建议。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • CEPH LIO iSCSI Gateway及其使用参考文档
    本文介绍了CEPH LIO iSCSI Gateway以及使用该网关的参考文档,包括Ceph Block Device、CEPH ISCSI GATEWAY、USING AN ISCSI GATEWAY等。同时提供了多个参考链接,详细介绍了CEPH LIO iSCSI Gateway的配置和使用方法。 ... [详细]
  • 本文介绍了一个React Native新手在尝试将数据发布到服务器时遇到的问题,以及他的React Native代码和服务器端代码。他使用fetch方法将数据发送到服务器,但无法在服务器端读取/获取发布的数据。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • 关于CMS收集器的知识介绍和优缺点分析
    本文介绍了CMS收集器的概念、运行过程和优缺点,并解释了垃圾回收器的作用和实践。CMS收集器是一种基于标记-清除算法的垃圾回收器,适用于互联网站和B/S系统等对响应速度和停顿时间有较高要求的应用。同时,还提供了其他垃圾回收器的参考资料。 ... [详细]
  • Java 11相对于Java 8,OptaPlanner性能提升有多大?
    本文通过基准测试比较了Java 11和Java 8对OptaPlanner的性能提升。测试结果表明,在相同的硬件环境下,Java 11相对于Java 8在垃圾回收方面表现更好,从而提升了OptaPlanner的性能。 ... [详细]
author-avatar
倚栏听风
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有