前言

多线程在面试中基本上已经是必问项了,面试官通常会从简单的问题开始发问,然后再一步一步的挖掘你的知识面。

比如,从线程是什么开始,线程和进程的区别,创建线程有几种方式,线程有几种状态,等等。

接下来自然就会引出线程池,Lock,Synchronized,JUC的各种并发包。然后就会引出 AQS、CAS、JMM、JVM等偏底层原理,一环扣一环。

这一节我们不聊其他的,只说创建线程有几种方式。

是不是感觉非常简单,不就是那个啥啥那几种么。

其实不然,只有我们给面试官解释清楚了,并加上我们自己的理解,才能在面试中加分。

正文

一般来说我们比较常用的有以下四种方式,下面先介绍它们的使用方法。然后,再说面试中怎样回答面试官的问题比较合适。

1、继承 Thread 类

通过继承 Thread 类,并重写它的 run 方法,我们就可以创建一个线程。

  • 首先定义一个类来继承 Thread 类,重写 run 方法。

  • 然后创建这个子类对象,并调用 start 方法启动线程。

2、实现 Runnable 接口

通过实现 Runnable ,并实现 run 方法,也可以创建一个线程。

  • 首先定义一个类实现 Runnable 接口,并实现 run 方法。

  • 然后创建 Runnable 实现类对象,并把它作为 target 传入 Thread 的构造函数中

  • 最后调用 start 方法启动线程。

3、实现 Callable 接口,并结合 Future 实现

  • 首先定义一个 Callable 的实现类,并实现 call 方法。call 方法是带返回值的。

  • 然后通过 FutureTask 的构造方法,把这个 Callable 实现类传进去。

  • 把 FutureTask 作为 Thread 类的 target ,创建 Thread 线程对象。

  • 通过 FutureTask 的 get 方法获取线程的执行结果。

4、通过线程池创建线程

此处用 JDK 自带的 Executors 来创建线程池对象。

  • 首先,定一个 Runnable 的实现类,重写 run 方法。

  • 然后创建一个拥有固定线程数的线程池。

  • 最后通过 ExecutorService 对象的 execute 方法传入线程对象。

到底有几种创建线程的方式?

那么问题来了,我这里举例了四种创建线程的方式,是不是说明就是四种呢?

我们先看下 JDK 源码中对 Thread 类的一段解释,如下图。

There are two ways to create a new thread of execution

翻译:有两种方式可以创建一个新的执行线程

这里说的两种方式就对应我们介绍的前两种方式。

但是,我们会发现这两种方式,最终都会调用 Thread.start 方法,而 start 方法最终会调用 run 方法。

不同的是,在实现 Runnable 接口的方式中,调用的是 Thread 本类的 run 方法。我们看下它的源码,

这种方式,会把创建的 Runnable 实现类对象赋值给 target ,并运行 target 的 run 方法。

再看继承 Thread 类的方式,我们同样需要调用 Thread 的 start 方法来启动线程。由于子类重写了 Thread 类的 run 方法,因此最终执行的是这个子类的 run 方法。

所以,我们也可以这样说。在本质上,创建线程只有一种方式,就是构造一个 Thread 类(其子类其实也可以认为是一个 Thread 类)。

而构造 Thread 类又有两种方式,一种是继承 Thread 类,一种是实现 Runnable接口。其最终都会创建 Thread 类(或其子类)的对象。

再来看实现 Callable ,结合 Future 和 FutureTask 的方式。可以发现,其最终也是通过  new Thread(task) 的方式构造 Thread 类。

最后,在线程池中,我们其实是把创建和管理线程的任务都交给了线程池。而创建线程是通过线程工厂类 DefaultThreadFactory 来创建的(也可以自定义工厂类)。我们看下这个工厂类的具体实现。

它会给线程设置一些默认值,如线程名称,线程的优先级,线程组,是否是守护线程等。最后还是通过 new Thread() 的方式来创建线程的。

因此,综上所述。在回答这个问题的时候,我们可以说本质上创建线程就只有一种方式,就是构造一个 Thread 类。(此结论借鉴来源于 Java 并发编程 78 讲 -- 徐隆曦)

个人想法

但是,在这里我想对这个结论稍微提出一些疑问(若有不同见解,文末可留言交流~)。。。

个人认为,如果你要说有 1种、2种、3种、4种 其实也是可以的。重要的是,你要能说出你的依据,讲出它们各自的不同点和共同点。讲得头头是道,让面试官对你频频点头。。

说只有构造 Thread 类这一种创建线程方式,个人认为还是有些牵强。因为,无论你从任何手段出发,想创建一个线程的话,最终肯定都是构造 Thread 类。(包括以上几种方式,甚至通过反射,最终不也是 newInstance 么)。

那么,如果按照这个逻辑的话,我就可以说,不管创建任何的对象(Object),都是只有一种方式,即构造这个对象(Object) 类。这个结论似乎有些太过无聊了,因为这是一句非常正确的废话。

以 ArrayList 为例,我问你创建 ArrayList 有几种方式。你八成会为了炫耀自己知道的多,跟我说,

  1. 通过构造方法,List list = new ArrayList();

  2. 通过 Arrays.asList("a", "b");

  3. 通过Java8提供的Stream API,如 List list = Stream.of("a", "b").collect(Collectors.toList());

  4. 通过guava第三方jar包,List list3 = Lists.newArrayList("a", "b");

等等,仅以上就列举了四种。现在,我告诉你创建 ArrayList 就只有一种方式,即构造一个 ArrayList 类,你抓狂不。

这就如同,我问你从北京出发到上海去有几种方式。

你说可以坐汽车、火车、坐动车、坐高铁,坐飞机。

那不对啊,动车和高铁都属于火车啊,汽车和火车都属于车,车和飞机都属于交通工具。这样就是只有一种方式了,即坐交通工具。

这也不对啊,我不坐交通工具也行啊,我走路过去不行么(我插眼传送也可以啊,就你皮~)。

最后结论就是,只有一种方式,那就是你人到上海即可。这这这,这算什么结论。。。

所以个人认为,说创建线程只有一种方式有些欠妥。

好好的一个技术文,差一点被我写成议论文了。。。

这个仁者见仁智者见智吧。

最后,我们看一下我从网上看到的一个非常有意思的题目。

有趣的题目

问:一个类实现了 Runnable 接口就会执行默认的 run 方法,然后判断 target 不为空,最后执行在 Runnable接口中实现的 run 方法。而继承 Thread 类,就会执行重写后的 run 方法。那么,现在我既继承 Thread 类,又实现 Runnable 接口,如下程序,应该输出什么结果呢?

public class TestThread {public static void main(String[] args) {new Thread(()-> System.out.println("runnable")){@Overridepublic void run() {System.out.println("Thread run");}}.start();}
}

可能乍一看很懵逼,这是什么操作。

其实,我们拆解一下以上代码就会知道,这是一个继承了 Thread 父类的子类对象,重写了父类的 run 方法。然后,父对象 Thread 中,在构造方法中传入了一个 Runnable 接口的实现类,实现了 run 方法。

现在执行了 start 方法,必然会先在子类中寻找 run 方法,找到了就会直接执行,不会执行父类的 run 方法了,因此结果为:Thread run 。

若假设子类没有实现 run 方法,那么就会去父类中寻找 run 方法,而父类的 run 方法会判断是否有 Runnable传过来(即判断target是否为空),现在 target 不为空,因此就会执行 target.run 方法,即打印结果:runnable。

所以,上边的代码看起来复杂,实则很简单。透过现象看本质,我们就会发现,它不过就是考察类的父子继承关系,子类重写了父类的方法就会优先执行子类重写的方法。

和线程结合起来,如果对线程运行机制不熟悉的,很可能就会被迷惑。


推荐阅读:

  • 看看人家那系统设计做的,那叫一个优雅

  • 漫话:为什么Java中的main方法必须是public static void的?

  • 那家注册了今日油条,饼多多,快手抓饼的公司终于被起诉了

  • 一个技术总监的忠告:精通那么多技术,你为何还是受不到重用?

喜欢我可以给我设为星标哦

好文章,我“在看”

面试官问我:创建线程有几种方式?我笑了相关推荐

  1. 创建线程的几种方式---最全面的创建线程方式总结---线程创建方式面试看这篇就够了

    前言:我相信创建线程的方式对于所有的java开发程序员来说都不陌生,在面试过程中这个问题也是高频考点.鉴于此,小编用本篇博文来整理几种线程的创建方式,希望对同学们有所帮助~ 文章目录 一.什么是进程? ...

  2. java 创建线程_【80期】说出Java创建线程的三种方式及对比

    点击上方"Java面试题精选",关注公众号 面试刷图,查缺补漏 >>号外:往期面试题,10篇为一个单位归置到本公众号菜单栏->面试题,有需要的欢迎翻阅. 一.Ja ...

  3. 创建线程的几种方式?JSP的九大内置对象及作用分别是什么?servlet的生命周期及常用方法?转发和重定向区别?ajax书写方式及内部主要参数都有哪些

    文章目录 1 , 创建线程的几种方式? 问题扩展: 2 ,JSP的九大内置对象及作用分别是什么? (1) 问题分析: (2) 核心答案讲解: 1.request对象 2.response对象 3.se ...

  4. 【并发编程】创建线程的四种方式

    上一篇我们初步认识了线程,现在我们来讲一下,创建线程的三种方式 1.继承Thread 类通过继承thread类,然后重写run方法(run方法中是线程真正执行的代码,runable也是如此)即可.当子 ...

  5. Java并发基础01. 传统线程技术中创建线程的两种方式

    传统的线程技术中有两种创建线程的方式:一是继承Thread类,并重写run()方法:二是实现Runnable接口,覆盖接口中的run()方法,并把Runnable接口的实现扔给Thread.这两种方式 ...

  6. 【并发技术01】传统线程技术中创建线程的两种方式

    传统的线程技术中有两种创建线程的方式:一是继承 Thread 类,并重写 run() 方法:二是实现 Runnable 接口,覆盖接口中的 run() 方法,并把 Runnable 接口的实现扔给 T ...

  7. Java创建线程的三种方式

    一.继承Thread类创建线程类 (1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务.因此把run()方法称为执行体. (2)创建Thread子类的实 ...

  8. Java-JUC(六):创建线程的4种方式

    Java创建线程的4种方式: Java使用Thread类代表线程,所有线程对象都必须是Thread类或者其子类的实例.Java可以用以下4种方式来创建线程: 1)继承Thread类创建线程: 2)实现 ...

  9. 创建线程的三种方式、线程运行原理、常见方法、线程状态

    文章目录 1.创建线程的三种方式 1.1 继承Thread类并重写run方法 1.2 使用Runnable配合Thread 1.3 通过Callable和FutureTask创建线程 2.Runnab ...

最新文章

  1. 基于小波变换的图像压缩解压缩仿真
  2. 项目管理在企业发展中的作用及未来的发展方向—— 来自项目管理群的讨论
  3. Modularity QuickStart学习
  4. mysql 分库分表 建表,mysql 分库分表 建表MySQL常用操作
  5. Mybatis入门程序
  6. Mac 解决 command not found: mysql
  7. 天地图专题六:复杂操作,天地图上标注点的连线以及模拟点击事件
  8. uva 1045(二分图最大权匹配)
  9. 计算机简单进制转换题目,计算机数制转换题!(1011011)2 =( )10=( )16 =( )8(110111101)2 =( )10=(...
  10. OpenOffice实现word文档在线预览
  11. python微信商城_GitHub - pythonsir/nideshop: NideShop 开源微信小程序商城服务端(Node.js + ThinkJS)...
  12. 详解Spring AOP原理
  13. 计算机按键去抖动的方式,按键消抖
  14. 生成微信公众号二维码(动态,彩色)(python)
  15. TCPIP之IP协议及IP地址详解
  16. WebRTC[52] - WebRTC 带宽分配逻辑详解
  17. Task3:第三回:布局格式定方圆
  18. error C2065: “pair”: 未声明的标识符
  19. 脚本:通过ssh、scp和expect批量复制文件到其它设备,已解决传输文件不完整的问题
  20. 标幺值下Simulink三相瞬时功率模块输出端加增益2/3的原因

热门文章

  1. 新余中山电子计算机学校,江西中山电子计算机中等专业学校2021年录取分数线多少...
  2. 非TOM-Skype版本的长话通(国内卡)拨号方法
  3. hexo 搭建个人博客
  4. 企业财务制度二--(二)负债类科目 2131 预收账款(转载)
  5. CCRC信息安全服务资质--安全运维申请
  6. “微信之父”张小龙的书单
  7. 服务器虚拟资源池,VMware服务器虚拟化功能介绍--存储DRS(资源池)、.docx
  8. Hadoop组件?Hadoop由什么组成?
  9. 清华大学出版社即将推出的又一本挂羊头卖狗肉的劣书 《C语言入门1.2.3—一个老鸟的C语言学习心得》...
  10. 中兴通讯股份有限公司(ZTE:Zhongxing Telecommunications Equipment)