Java实现多线程有几种方式(满分回答)
目录
- JDK8 创建的线程的两种方式
- orcle文档解释
- 方式一:继承Thread类
- 方式二:实现Runnable接口
- 同时用两种的情况
- 其他间接创建方式
- Callable接口
- 线程池
JDK8 创建的线程的两种方式
orcle文档解释
orcle文档:https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html
总结:
准确的讲,创建线程只有一种方式那就是构造Thread类,而实现线程的执行单元有两种方式:
- 方法一:实现
Runnable接口
的重写run方法,并把Runnable
实例传给Thread类 - 方法二∶重写
Thread
的run
方法(继承Thread类)
(其他一些方式,究其根本都是间接的通过上面两种方式创建的)
方式一:继承Thread类
public static void main(String[] args) {System.out.println("主线程运行:" + Thread.currentThread().getName());Task1 task = new Task1();task.start();}static class Task1 extends Thread{@Overridepublic void run() {for (int i = 0; i < 20; i++) {System.out.println("task1线程运行" + Thread.currentThread().getName());System.out.println("Task11继承Thread实现多线程");}}}}
自定义线程类继承Thread类
重写run()方法,编写线程执行体
创建线程对象,调用start()方法启动线程
方式二:实现Runnable接口
public static void main(String[] args) {Task task = new Task();Thread thread = new Thread(task);thread.start();}static class Task implements Runnable{@Overridepublic void run() {for (int i = 0; i < 20; i++) {System.out.println("task1线程运行" + Thread.currentThread().getName());System.out.println("Task11实现Runnable接口实现多线程");}}}
定义MyRunnable类实现Runnable接口
实现run()方法,编写线程执行体
创建线程对象,调用start()方法启动线程
同时用两种的情况
public static void main(String[] args) {new Thread(new Runnable() {@Overridepublic void run() {System.out.println("实现Runnable的run方法");}}){@Overridepublic void run() {System.out.println("匿名内部类,重写Thread类的run方法");}}.run();
}
结果:
匿名内部类,重写Thread类的run方法
分析:
这里使用的匿名内部类,在匿名内部类里面又重写了Thread类的run方法。创建Thread类的同时传入了Runnable对象,这时候Thread类的run已被重写,不再是原生方法的逻辑:执行传入task的run
所以即便传入Runnable,也不会被执行。
其他间接创建方式
Callable接口
public static void main(String[] args) {Task task = new Task();FutureTask<Integer> ft = new FutureTask<>(task);Thread thread = new Thread(ft);thread.start();}static class Task implements Callable<Integer> {@Overridepublic Integer call() throws Exception {for (int i = 0; i < 20; i++) {System.out.println("task1线程运行" + Thread.currentThread().getName());System.out.println("Task11实现Callable接口实现多线程");}return 1;}
}
FutureTask
实现了RunnableFuture
接口,RunnableFuture
继承了Runnable
和 Future
接口。所以也是间接通过Runnable
来创建的。
- 实现Callable接口,需要返回值类型
- 重写call方法,需要抛出异常
- 创建目标对象
- 创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
- 提交执行:Future result1 = ser.submit(t1);
- 获取结果: boolean r1 = result1.get()
- 关闭服务: ser.shutdownNow();
实现Runnable接口和Callable接口的区别
- Runnable 接口不会返回结果,Callable 接口可以返回结果
- Callable接口实现类中的run方法允许异常向上抛出,可以在内部处理,try catch,但是runnable接口实现类中run方法的异常必须在内部处理,不能抛出
线程池
ThreadPoolExecutor
类的execute
方法:
public void execute(Runnable command) {if (command == null)throw new NullPointerException();/** Proceed in 3 steps:** 1. If fewer than corePoolSize threads are running, try to* start a new thread with the given command as its first* task. The call to addWorker atomically checks runState and* workerCount, and so prevents false alarms that would add* threads when it shouldn't, by returning false.** 2. If a task can be successfully queued, then we still need* to double-check whether we should have added a thread* (because existing ones died since last checking) or that* the pool shut down since entry into this method. So we* recheck state and if necessary roll back the enqueuing if* stopped, or start a new thread if there are none.** 3. If we cannot queue task, then we try to add a new* thread. If it fails, we know we are shut down or saturated* and so reject the task.*/int c = ctl.get();//如果工作线程数小于核心线程数,if (workerCountOf(c) < corePoolSize) {//执行addWorker,会创建一个核心线程,如果创建失败,重新获取ctlif (addWorker(command, true))return;c = ctl.get();}//如果工作线程数大于等于核心线程数,线程池的状态是RUNNING,并且可以添加进队列//(RUNNING状态下)如果添加失败,说明是队列已经满了,接着就去创建新的线程,如果大于最大线程数,则执行拒绝策略//如果线程池不是RUNNING状态,则执行拒绝策略(当然还会调addWorker进行判断一次)if (isRunning(c) && workQueue.offer(command)) {//再次获取ctl,进行双重检索(也就是对线程池的状态再次检查一遍)int recheck = ctl.get();//如果线程池是不是处于RUNNING的状态,那么就会将任务从队列中移除,//如果移除失败,则会判断工作线程是否为0 ,如果过为0 就创建一个非核心线程//如果移除成功,就执行拒绝策略,因为线程池已经不可用了;if (! isRunning(recheck) && remove(command))reject(command);else if (workerCountOf(recheck) == 0)addWorker(null, false);}else if (!addWorker(command, false))//线程池挂了或者大于最大线程数reject(command);
}
addWork
方法会创建线程池内工作线程Worker
。Worker
这个线程,实现了Runnable
接口,并持有一个线程thread,一个初始化的任务firstTask。thread是调用构造方法时通过ThreadFactory
来创建的线程
ThreadFactory
中也是Runnable
创建线程的模式。
Java实现多线程有几种方式(满分回答)相关推荐
- Java 实现多线程的四种方式 超详细
Java 实现多线程的四种方式 文章目录 Java 实现多线程的四种方式 一.继承 Thread 类 二.实现 Runnable 接口 三.实现 Callable 接口 四.线程池 1,Executo ...
- java创建多线程的四种方式
java多线程的创建方式是面试经常会被问到的一个问题,因此在这里我对java创建多线程的四种方式做一个简单的归纳与总结,便于复习. 一.继承Thread类创建多线程 ① 创建一个继承于Thread类的 ...
- JAVA实现多线程的三种方式
在Java中可通过三种方式来实现多线程: 1.继承Thread类,重写run( )方法 2.实现Runnable接口,重写run( )方法 3.实现Callable接口,重写call( )方法并使用F ...
- Java 实现多线程的四种方式
在 Java 中实现多线程一共有四种方式: 继承 Thread 类 实现 Runnable 接口 实现 Callable 接口 线程池 下面我将对这四种方式进行入门级的解析和演示. 一.继承 Thre ...
- Java实现多线程的几种方式
Java实现多线程主要有三种方式:继承Thread类.实现Runnable接口.使用ExecutorService.Callable.Future实现由返回结果的多线程.其中前两种方式线程执行完之后是 ...
- Java实现多线程的两种方式讲解
1.两种方式 继承Thread和实现Runnable接口 a.Runnable 是一个接口,该接口中只包含了一个run()方法.我们可以定义一个类A实现Runnable接口:然后,通过ne ...
- Java实现多线程的两种方式
认识多线程之前,我们先要了解几个关于多线程有关的概念. A:进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. B:线程 ...
- java实现多线程的4种方式
1.继承Thread类 看jdk源码可以发现,Thread类其实是实现了Runnable接口的一个实例,继承Thread类后需要重写run方法并通过start方法启动线程. 继承Thread类耦合性太 ...
- java多线程w3c_Java创建多线程的三种方式
前言 这篇文章主要讲述线程的概念.组成.Java创建多线程的三种方式以及线程的类型. 线程概念 线程和进程的区别 **进程:**正在运行的程序,例如:你打开 的qq音乐.exe程序,其由PCB(进程控 ...
最新文章
- 由于检索用户的本地应用程序数据路径时出错,导致无法生成 SQL Server 的用户实例...
- auto errored after 报错解决_MySQL5.7 group_by报错问题解决办法,大部分程序员都收藏了...
- 关于docker的日常操作(二)
- 精美教师说课试讲教学通用PPT模板
- 腾讯云短信封装(v3版本)
- web高拍仪图片上传
- html消息对话框,添加消息对话框 (HTML)
- 计算机里的文件夹可以加密吗,如何加密电脑中的文件夹
- linux的ip是什么,Linux-IP地址后边加个/8(16,24,32)是什么意思?
- 用accelstepper库控制28BYJ-48步进电机(快慢运动切换)
- axis的xml转java的实际开发使用笔记
- java计算机毕业设计小区物业管理系统源码+系统+数据库+lw文档+mybatis+运行部署
- QT5.6 安装 过程,实践经历……
- Flink触发器Triggers
- 颁奖 | 获奖名单又来惹~!有你咩?
- idea E9 OA环境搭建
- 除了 Android 12,Google I/O 开发者大会还有哪些亮点?
- matlab模拟角度调制系统的仿真与设计,基于Matlab的模拟通信系统的仿真设计
- d2-admin-路由菜单
- JasperReports配置中文字体
热门文章
- 华为鸿蒙是系统还是处理器,华为将发布MatePad Pro:搭载鸿蒙系统,麒麟9000处理器...
- 安卓查看内存读写测试软件_装机小贴士:内存双通道重要吗
- html加css绘制oprea的logo,css – 在Opera和webkit中自定义字体的底部
- 学计算机的怎样当老师,“年薪50万,不如安心当老师”,过来人揭开千万人报考教资的真相...
- IDEA 自动导包设置
- 对诗词与人生之间关系的几点思考
- 设置 win10 开机自动登录
- 图书馆座位预约系统(Django框架)
- nofollow标签是什么?有用吗?如何添加?
- Werewolf——困难版本