java创建线程的四种方法
第一种:通过继承Thread类创建线程
第二种: 通过实现Runnable接口创建线程
这两种早已烂记于心,这里就不作过多的介绍, 主要介绍其源码
Thread类 implements Runnable
文章图片
thread空线程的run方法 是判断target是否存在实,再执行target实例中的run方法
public void run(){ if(this.target != null){ this.target.run(); } }
通过实现Runnable接口, 并且通过thread构造函数创建线程的方法
Runnable runnable = new Runnable(){...重写run方法}; Thread thread_one = new Thread(runnable); Thread thread_two = new Thread(runnable);
如果创建多个线程, 实质是多个线程引用同一个target 实例
对比两种方式的区别:
通过继承Thread类实现多线程的方式由于单继承的局限性, 不能再继承其他类, 只能完成各自的任务
通过实现Runnable接口实现多线程的方式能更好的做到并发完成同一个任务, 因为访问的是同一个target, 实现了共享数据
【java创建线程的四种方法】总之,在大多数情况下,都偏向于通过实现Runnable接口创建多线程
第三种: 使用Callable接口 和 FutureTask类创建线程
由于Thread类和Runnbale接口中的run方法没有返回值, 所以这两种方式不能获取异步执行的结果
Callable接口
package java.util.concurrent; @FunctionalInterface public interface Callable{ V call() throws Exception; }
@FunctionalInterface 注解标注在接口上, 表示此接口为"函数式接口"
函数式接口:只有一个抽象方法的接口
此注解只是方便编译器进行检查, 不加也不会影响. 如果加了注解但该接口不是函数式接口,编译器会报错
Callable接口是泛型接口 ,也是函数式接口
call()抽象方法还有一个Exception的异常声明, 容许方法内的异常直接抛出,并且可以不予捕获
文章图片
Future接口, RunnableFuture接口,以及FutureTask实现类都是位于 java.util.concurrent包下
V get()用于阻塞性得到异步执行的结果.此方法是阻塞性的,异步未执行完会处于阻塞状态
Object outcome用于保存call()方法的异步执行结果.get()会获取
创建线程的具体步骤
class ReturnableTask implements Callable{ public long call() throws Exception{ //线程要执行的代码 } }public static void main(String args[]) throws InterruptedException{ ReturnableTask task= new new ReturnableTask(); Futuretask FutureTask = new Futuretask (task); Thread thread = new Thread(FutureTask,"returnableThread"); thread.start(); System.out.println(FutureTask.get()); //得到异步执行结果 }
下图为具体实现过程
文章图片
两个线程处于并发状态, 默认异步执行
看起来两个线程是同时进行,实质上是不是, 单个进程在同一时间只能执行一个进程,由于分给线程的时间片非常短(线程切换毫秒级),所以以为是同时
并发执行的消息通信机制分为同步和异步,这些就不做过多解释
总之,图上的两个线程不是同时运行
第四种: 通过线程池创建线程
通过Thread创建线程在执行完就被销毁了, 不可服用. 在高并发场景中, 频繁创建线程是非常消耗资源的, 通过线程池创建线程可以对已经创建好的线程进行复用
Executors 静态工厂类用于创建不同的线程池 java.util.concurrent;
//创建一个包含三个线程的线程池 private static ExecutorService pool = Executors.newFixedThreadPool(3);
Executor接口
void executo(Runnable command); //执行Runnable类型
ExecutorService
Future> submit(Runnable task)//提交Runnable类型以执行
具体实现
main Future future= pool.submit(new RuturnableTask()); Long result = (Long) future.get(); //得到异步执行的结果
execute() 与 submit() 执行线程方法的区别
execute()只能执行Runnable, 并且无返回值
submit() 既能执行Runnable又能执行callable, 并且有返回值
注: 实际生产环境中禁止使用Executors创建线程池
推荐阅读
- 详解JavaScript中任意两数加减的解决方案
- 在|在 CRM WebClient UI 中使用纯 JavaScript 显示 3D 足球效果
- 前端|彻底吃透 JavaScript 执行机制
- 知识总结|Java基础知识总结(超级详细-面试必备)
- Java基础知识点|Java基础知识点总结归纳,超级全面!(2021版)
- JAVA基础|JAVA基础知识汇总(思维导图)
- java|java8 Stream中reduce方法 属于fold方法的一种 以及对应化简
- 操作系统|linux下创建和删除软、硬链接
- 前端|JS基本功修炼,一文搞懂JavaScript数组
- 前端|vite.config.js中vite.defineConfig is not defined以及创建最新版本的vite项目