• Java面试挂在线程创建后续,不要再被八股文误导了!创建线程的方式只有1种


    写在开头

    在上篇博文中我们提到小伙伴去面试,面试官让说出8种线程创建的方式,而他只说出了4种,导致面试挂掉,在博文中也给出了10种线程创建的方式,但在文章的结尾我们提出:真正创建线程的方式只有1种,剩下的衍生品多是套壳,那么在这篇文章中,我们来解释一下缘由!
    线程创建方式可先阅读这篇文章:面试官让说出8种创建线程的方式,我只说了4种,然后挂了。。。

    线程创建之源

    OK!咱们闲话少叙,直接进入正题,回顾一下通过实现Runnable接口,重写run方法创建线程的方式,真的可以创建一个线程吗?来看下面这段demo。

    【代码示例1】

    public class Test implements Runnable{
    public static void main(String[] args) {
    Test test = new Test();
    test.run();
    }
    @Override
    public void run() {
    System.out.println(Thread.currentThread().getName()+":"+"runnable线程");
    }
    }

    输出:

    main:runnable线程

    虽然这里我们实现了Runnable接口并重写了run方法,但执行结果中输出的线程却是主线程,这可我们调用普通的方法一样,仍旧依靠的主线程驱动,那怎么样创建一个线程呢?

    【代码示例2】

    public class Test implements Runnable{
    public static void main(String[] args) {
    Test test = new Test();
    new Thread(test).start();
    }
    @Override
    public void run() {
    System.out.println(Thread.currentThread().getName()+":"+"runnable线程");
    }
    }

    输出:

    Thread-0:runnable线程

    这个demo中,我们在外面套了一层Thread,然后调用start方法,最终输出的结果就是一个全新的Thread-0线程,从而实现了线程的创建。

    得出结论

    我们继续换Callable、FutureTask、ThreadGroup、匿名内部类或Lambda表达式等类或接口,发现均无法直接创建一个线程,必须借助Thread的start();

    而例如ExecutorService线程池、ForkJoin线程池、CompletableFuture类、Timer定时器类、parallelStream并行流等等,如果有去看过它们源码的小伙伴应该清楚,它们最终都依赖于Thread.start()方法创建线程。

    因此,我们在这里可以大胆的得出这样的一个结论:

    在Java中创建线程的方式只有一种:通过Thread.start()调用 start()方法,会启动一个线程并使线程进入就绪状态,当分配到时间片后开始运行。 start() 会执行线程的相应准备工作,然后自动执行 run() 方法的内容

    线程体与线程的区别

    文章写到这里,我们一起再来思考一个问题,既然Runnable和Callable接口和Thread类一样需要重写他们提供的run()/call()方法,又没有创建线程,那它们究竟做了什么呢?
    这个直接给出答案:他们经过重写,确定了线程体,那线程体与线程又有何区别?我们来看看文心一言怎么说。
    image

    总结一句话:线程体是线程的核心部分,负责执行线程的具体任务。

    所以说无论是Thread中的run还是Runnable中的run,Callable中的call方法,内部所实现的都是线程需要执行的具体内容也就是线程体

    总结

    基于以上的分析,若我们在面试中再次遇到:“Java线程有几种创建方式?”的考题,就可以这样回答啦:

    Java中创建线程的方式有很多种,在《Java技术卷》和《Java编程思想》中提供了实现Runnable、Callable接口、继承Thread类、创建线程池这四种常见方式,我们还可以通过ForkJoin线程池、CompletableFuture类、Timer定时器类、parallelStream并行流、匿名内部类或Lambda表达式等多种方式去实现,但这些都不是真正意义上的创建线程,严格意义上,Java创建线程的方式只有一种那就是通过new Thread().start()创建,Runnable、Callable接口只是重写了线程的线程体,用来确定我们线程需要执行的内容。

    结尾彩蛋

    如果本篇博客对您有一定的帮助,大家记得留言+点赞+收藏呀。原创不易,转载请联系Build哥!

    image

    如果您想与Build哥的关系更近一步,还可以关注“JavaBuild888”,在这里除了看到《Java成长计划》系列博文,还有提升工作效率的小笔记、读书心得、大厂面经、人生感悟等等,欢迎您的加入!

    image

  • 相关阅读:
    垂直分表、分布式Id详细介绍、模板引擎FreeMarker、对象存储服务MinIO(黑马头条Day02)
    ChatGPT在数据分析学习阶段的应用
    代码随想录Day03 | 链表基础1 LeetCode T203 移除链表元素 T707设计链表 T206 反转链表
    CTFHUB
    5毛VS600亿,食品安全问题是卫龙上市最大的拦路虎?
    C++的跨平台(Linux)开发——总结
    一起Talk Android吧(第四百回:Glide的基本用法)
    ethtool netlink 框架原理浅析
    【clickhouse专栏】数据库、数据仓库之间的区别与联系
    Vuex的简单购物车案例以及页面刷新数据丢失的解决方法
  • 原文地址:https://www.cnblogs.com/JavaBuild/p/18060227