实现多线程的方法到底有1种还是2种还是4种?
目录
- 1、Oracle官网的文档是如何写的?
- 2、两种方法的对比
- 3、思考题:同时用两种方法会怎么样?
- 4、总结:最精准的描述
- 5、典型错误观点分析
- 6、典型错误观点总结
- 7、实现多线程——常见面试问题
1、Oracle官网的文档是如何写的?
- 方法一:实现Runnable接口
- 方法二:继承Thread类
实现Runnable接口
package threadcoreknowledge.createthreads;/*** 描述: 用Runnable方式创建线程*/
public class RunnableStyle implements Runnable{public static void main(String[] args) {Thread thread = new Thread(new RunnableStyle());thread.start();}public void run() {System.out.println("用Runnable方式创建线程");}
}
继承Thread类
package threadcoreknowledge.createthreads;/*** 描述: 用Thread方式实现线程*/
public class ThreadStyle extends Thread{@Overridepublic void run() {System.out.println("用Thread方式实现线程");}public static void main(String[] args) {new ThreadStyle().start(); }
}
2、两种方法的对比
方法1(实现Runnable接口)更好。
方法2的缺点:
- 从代码的架构来考虑,具体执行的任务(run方法里面的内容)应该是和Thread解耦的,不应该把这两件事情混为一谈;
- 从资源的节约上,继承了 Thread 类,每次我们想新建一个任务只能去新建一个独立的线程,而新建一个独立的线程损耗是十分大的(因为需要去创建,销毁);
- 继承了Thread 类,由于Java不支持双继承,导致这个类无法去继承其他类了,这大大限制了代码的可扩性。
两种方法的本质对比
- 方法一:最终调用target.run();
@Overridepublic void run() {if (target != null) {target.run();}}
- 方法二:run()整个都被重写
3、思考题:同时用两种方法会怎么样?
package threadcoreknowledge.createthreads;/*** 描述 同时使用Runnable和Thread两种实现线程的方式*/
public class BothRunnableThread {public static void main(String[] args) {new Thread(new Runnable() { //传入Runnable对象@Overridepublic void run() {System.out.println("我来自Runnable");}}){@Override //重写run()方法public void run() { System.out.println("我来自Thread");}}.start();}
}
代码执行结果:
从面向对象的思想去考虑: 因为我们重写了run()方法,所以导致Thread的三行run()方法代码不再存在,即使传入传入Runnable对象,它也不再执行。
4、总结:最精准的描述
1、通常我们可以分为两类,Orracle也是这么说的
2、准确的讲,创建线程只有—种方式那就是构造Thread类,而实现线程的执行单元有两种方式
- 方法一:实现Runnable接口的run方法,并把Runnable实例传给Thread类;
- 方法二:重写Thread的run方法(继承Thread类)。
5、典型错误观点分析
1、“线程池创建线程也算是一种新建线程的方式”
package threadcoreknowledge.wrongways;import javafx.concurrent.Task;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPools {public static void main(String[] args) {ExecutorService executorService = Executors.newCachedThreadPool();for (int i = 0; i < 1000; i++) {executorService.submit(new Tasks() {});}}
}
class Tasks implements Runnable{@Overridepublic void run() {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName());}
}
代码执行结果:
public Thread newThread(Runnable r) {Thread t = new Thread(group, r,namePrefix + threadNumber.getAndIncrement(),0);if (t.isDaemon())t.setDaemon(false);if (t.getPriority() != Thread.NORM_PRIORITY)t.setPriority(Thread.NORM_PRIORITY);return t;
}
点进去源码可以看到,线程池本质创建线程的方法是new Thread
,因此这并不是一种新的创建线程方式 。
2、“通过Callable和FutureTask创建线程,也算是一种新建线程的方式”
本质是实现Runnable接口和继承Thread类实现的。
3、“无返回值是实现runnable接口,有返回值是实现callable接口,所以callable是新的实现线程的方式”
本质依旧是实现Runnable接口和继承Thread类实现的。
4、定时器
package threadcoreknowledge.wrongways;import java.util.Timer;
import java.util.TimerTask;/*** 描述: 定时器创建线程*/
public class DemoTimerTask {public static void main(String[] args) {Timer timer = new Timer();timer.scheduleAtFixedRate(new TimerTask() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName());}},1000,1000);}
}
代码执行结果:
5、匿名内部类
package threadcoreknowledge.wrongways;public class AnonymousInnerClassDemo {public static void main(String[] args) {new Thread(){@Overridepublic void run() {System.out.println(Thread.currentThread().getName());}}.start();new Thread(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName());}}).start();}
}
代码执行结果:
本质一样。
6、Lambda表达式
package threadcoreknowledge.wrongways;public class Lambda {public static void main(String[] args) {new Thread(()-> System.out.println(Thread.currentThread().getName())).start();}
}
代码执行结果:
本质一样。
6、典型错误观点总结
多线程的实现方式,在代码中写法千变万化,但其本质万变不离其宗。他们通过各种各样的包装,比如线程池,定时器,包装的外表好像是实现线程池的一种方式,但是我们打开包装透过源码去看到他最终实现的道理的话,本质其实是实现Runnable接口和继承Thread类。
7、实现多线程——常见面试问题
有多少种实现线程的方法?思路有5点:
- 从不同的角度看,会有不同的答案。
- 典型答案是两种
- 我们看原理,两种本质都是一样的
- 具体展开说其他方式
- 结论
实现Runnable接口和继承Thread类哪种方式更好?
- 从代码架构角度
- 新建线程的损耗
- Java不支持双继承
实现多线程的方法到底有1种还是2种还是4种?相关推荐
- 利用多线程解决多业务不同定时区间歇触发问题的一种方法
利用多线程解决多业务不同定时区间歇触发问题的一种方法 参考文章: (1)利用多线程解决多业务不同定时区间歇触发问题的一种方法 (2)https://www.cnblogs.com/naaoveGIS/ ...
- python多线程实现方法_Python3 多线程的两种实现方式
最近学习 Python3 ,希望能掌握多线程的使用,在此做个笔记.同时也希望Python 牛人指点错误.关于线程的概念,前面简单总结了一下 java 的多线程,传送门:java 多线程概念,三种创建多 ...
- 实现多线程的方法有哪几种?
1)实现Runnable接口,并实现该接口的run()方法. 自定义类并实现Runnable接口,实现run()方法 创建Thread对象,用实现Runnable接口的对象作为参数实例化该Thread ...
- java中实现多线程的方法有哪几种
实现多线程的方法有三种: 实现Runnable接口,并实现接口的run()方法 继承Thread类,重写run方法 实现Callable接口,重写call()方法 实现Runnable接口,并实现接口 ...
- Java多线程优化方法及使用方式
一.多线程介绍 在编程中,我们不可逃避的会遇到多线程的编程问题,因为在大多数的业务系统中需要并发处理,如果是在并发的场景中,多线程就非常重要了.另外,我们在面试的时候,面试官通常也会问到我们关于多线程 ...
- Qt中使用多线程的一些心得(一)——继承QThread的多线程使用方法
一 前言 二Qt多线程方法一 继承QThread 2.1使用多线程的原因分析 2.2 写一个继承于QThread的线程 三 总结 一 前言 本篇文章部分内容参考了该博文:传送门. Qt中有两种 ...
- 深入探索多线程优化方法
前言 什么是线程的概念我就不在介绍,不懂的自行百度,我想百分之九十九的人都是知道的,至于多线程,通俗的就是有很多的线程在一起工作从而完成某一件事,从而提升效率.这就是使用多线程的好处之一,举个列子,一 ...
- Java多线程(一)——多线程实现方法和生命周期
目录 一.引言 二.多进程与多线程 三.实现方法 1.继承Thread接口 2.实现runnable接口,传入Thread运行 3.注意 四.生命周期 五.总结 一.引言 之前多线程了解的基本是皮毛, ...
- QT 中多线程实现方法总结
第一: 用QtConcurrentRun类,适合在另一个线程中运行一个函数.不用继承类,很方便 第二:用QRunnable和QThreadPool结合.继承QRunnable,重写run函数,然后用Q ...
最新文章
- python之人脸识别
- QQ开心农场外挂软件设计思路
- MathType插入带序号公式的两种方法
- 使用Hadoop自带的例子wordcount实现词频统计
- java main spring_分享通过在java main函数中执行spring的代码
- 一些有趣的 CSS 魔法和布局(下)(结尾有岗位内推哦~)
- 昨天凌晨故宫网站崩了,被众多人“围攻”!留言亮了...
- Python实现图像信息隐藏
- JDK8启动时,参数传递过程
- html在线比对工具,在线文本对比工具(mergely示例)
- 未授权访问漏洞测试方法及修复方案
- Link第一次打包与部署笔记
- 鸿蒙HarmonyOS开发环境初识及搭建
- C语言机器人视觉系统原理,机器人视觉系统工作原理
- jsrun怎么拿里面的代码?
- 清除win+r的记录
- SQL Server研习录(08)——LEFT()函数
- html5 游戏 限制,HTML5新技术让游戏解决了三个大问题
- @value()注解
- Python之子域名查询