多线程与高并发(14)——Executor框架(线程池基础)

news2024/11/18 19:58:56

一、简介

线程是什么,线程是一个任务的工作单元和执行单元。我们在用线程的时候知道,要创建线程,再执行线程。如果任务多的情况呢,会有大量的创建销毁线程的资源消耗,这时候就引入了线程池的概念。
JDK5开始,把工作单元和执行单元分开,工作单元包括Runnable和Callable,利用Executor来执行任务。
通过 Executor来启动线程比使用 Thread 的 start 方法更好,除了更易管理,效率更好(用线程池实现,节约开销)外,还有关键的一点:有助于避免 this 逃逸问题。
this 逃逸是指在构造函数返回之前其他线程就持有该对象的引用,调用尚未构造完全的对象的方法可能引发令人疑惑的错误。

二、Executor框架结构

1、任务: 包括被执行任务需要实现的接口,Runnable接口或者Callable接口。
2、任务的提交和执行: 包括任务执行机制的核心接口Executor,以及继承自Executor的ExecutorService接口。Executor框架有两个关键类实现了ExecutorService接口(ThreadPoolExecutor和ScheduleThreadPoolExecutor)。ExecutorService接口中补充了任务的提交方法submit()。
3、任务的结果(异步计算): 包括接口Future和实现Future接口的FutureTask类。
Executor翻译过来就是执行器的意思,也就是说,Executor框架的目的就是调度任务进行执行,并得出异步计算的结果。

1、任务(Runnable和Callable接口)

主线程通过实现 Runnable 或者 Callable 接口,创建任务对象,用于后续执行。
Runnable或Callable接口的实现类都可以被 ThreadPoolExecutor 或ScheduledThreadPoolExecutor 执行。
区别:Runnable接口不会抛异常或者返回对象,但是 Callable 接口可以。
代码如下:

@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}
@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

2、任务的提交和执行

Executor常用的类图如下:
在这里插入图片描述
任务执行机制的核心接口 Executor源码如下:

public interface Executor {

    /**
     * Executes the given command at some time in the future.  The command
     * may execute in a new thread, in a pooled thread, or in the calling
     * thread, at the discretion of the {@code Executor} implementation.
     *
     * @param command the runnable task
     * @throws RejectedExecutionException if this task cannot be
     * accepted for execution
     * @throws NullPointerException if command is null
     */
    void execute(Runnable command);
}

通过代码可以看出,其中定义了任务的执行。
execute()方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功与否;
ExecutorService接口中提供了submit()方法,用于提交需要返回值的任务。
代码如下:

<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);

线程池会返回一个 Future 类型的对象。

3、任务的结果

Future存储的是未来产生的一个结果,其中的get()方法是阻塞的,用来获取返回值。
代码如下:

	V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;

使用 get(long timeout,TimeUnit unit)方法的话,如果在 timeout 时间内任务还没有执行完,就会抛出 java.util.concurrent.TimeoutException。
FutureTask接口表示Future+Runnable,其类图如下:
在这里插入图片描述
FutureTask表示可以直接创建一个FutureTask对象,交给线程池去执行,并且有返回结果。

三、Executor框架使用

下面这个图出现的次数很多了:
在这里插入图片描述
1、主线程创建任务对象,这个任务对象实现了Runnable或 Callable接口。
2、把任务对象交给执行器ExecutorService去执行:

ExecutorService.execute(Runnable command);
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);

3、主线程可以直接创建一个FutureTask对象交给执行器去执行。
4、主线程可以执行 FutureTask.get()方法来等待任务执行完成。主线程也可以执行 FutureTask.cancel(boolean mayInterruptIfRunning)来取消此任务的执行。

四、 示例代码

1、Future

submit()和get()方法:

 public static void main(String[] args) throws ExecutionException, InterruptedException {
        //线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        //提交并执行任务
        Future<String> submit = executorService.submit(() -> {
            try {
                Thread.sleep(5000L);
                System.out.println("5秒过去啦");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "我是返回值";
        });

        String s = submit.get();
        System.out.println(s);
        //关闭线程池
        executorService.shutdown();
    }

结果如下:

5秒过去啦
我是返回值

get(long timeout,TimeUnit unit)方法:

public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        //线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        //提交并执行任务
        Future<String> submit = executorService.submit(() -> {
            try {
                Thread.sleep(5000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "我是返回值";
        });
        //3秒就不行了哦
        String s = submit.get(3, TimeUnit.SECONDS);
        System.out.println(s);
        //关闭线程池
        executorService.shutdown();
    }

运行结果如下:
在这里插入图片描述
抛出异常,且线程阻塞未结束。

2、Callable

 public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        //创建任务
        Callable<String> callable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                return "我是callable";
            }
        };
        //线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        //提交并执行任务
        Future<String> submit = executorService.submit(callable);
        //3秒就不行了哦
        String s = submit.get(3, TimeUnit.SECONDS);
        System.out.println(s);
        //关闭线程池
        executorService.shutdown();
    }

执行结果如下:

我是callable

3、FutureTask

public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        //线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        //创建并执行任务
        FutureTask<String> task = new FutureTask<>(()->{
            return "aaaaaaa";
        });
        executorService.submit(task);
        String s = task.get();
        System.out.println(s);
        //关闭线程池
        executorService.shutdown();
    }

执行结果如下:

aaaaaaa

五、总结&&常见对比

1、Runnable vs Callable

前者无返回值和抛异常,后者有。

2、execute vs submit

前者执行不需要返回值的任务,后者执行需要返回值的任务,返回值为Future。

3、shutdown vs shutdownNow

shutdown() :关闭线程池,线程池的状态变为 SHUTDOWN。线程池不再接受新任务了,但是队列里的任务得执行完毕。(新任务停止,已存在的要执行完
shutdownNow():关闭线程池,线程的状态变为 STOP。线程池会终止当前正在运行的任务,并停止处理排队的任务并返回正在等待执行的 List。(停止所有任务并返回等待值

4、isTerminated vs isShutdown

isTerminated () :调用 shutdown() 方法后,并且所有提交的任务完成后返回为 true。
isShutdown():调用 shutdown() 方法后返回为 true。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/72536.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用Maven创建Servlet项目

创建Maven项目 点击FIle, 选择new ,选择Project… 选择Maven 然后点击next. 选择自己想要创建项目的目录.点击next 引入依赖 在pom.xml中添加servlet依赖. 先书写dependencies标签.然后在 Maven中央仓库 中找到servlet的依赖.复制填写进去. 这里是我常用的一个 Maven中央仓库…

TI Lab_SRR学习_3 速度扩展_2 interChirpProcessing_RangeDPU

RangeProcDSP共分为三步,如下图所示 transfers ADCBuf data through dataIn EDMA channels in ping/pong alternate order to FFT input scratch buffer - adcDataIn.Range FFT processing is done by using DSPlib and mmwavelib APIs. FFT input data is stored in input sc…

[附源码]计算机毕业设计JAVA中青年健康管理监测系统

[附源码]计算机毕业设计JAVA中青年健康管理监测系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM …

Python 实战分析某招聘网站数据分析岗位的招聘情况

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~ 今天案例难度指数: ☆☆☆ 准备 环境使用&#xff1a; Anaconda (python3.9) –>识别我们写的代码 开发工具&#xff1a; jupyter notebook –>代码编辑功能敲代码的工具 相关模块&#xff1a; seaborn pandas …

在CentOS7.9系统上安装N卡3060驱动、CUDA和离线升级gcc(4.8—>8.3)用以编译框架的过程记录

1、更换yum源 主要是在终端操作需要&#xff0c;在显示器界面可以直接联网解决网络问题进行软件安装或更新 """"备份原来的源""" mv /etc/yum.repos.d/ /etc/yum.repos.d.bak/ mkdir /etc/yum.repos.d vim /etc/yum.repos.d/xxx.repo &qu…

LeetCode HOT 100 —— 155.最小栈

题目 设计一个支持 push &#xff0c;pop &#xff0c;top 操作&#xff0c;并能在常数时间内检索到最小元素的栈。 实现 MinStack 类: MinStack() 初始化堆栈对象。 void push(int val) 将元素val推入堆栈。 void pop() 删除堆栈顶部的元素。 int top() 获取堆栈顶部的元素。 …

JavaScript 删除对象中的某一项

delete let obj{a:1,b:2,c:3,d:4,e:5,f:6} delete obj.b console.log(obj)运行结果&#xff1a; Reflect.deleteProperty JavaScript 中的静态方法 Reflect.deleteProperty() 允许用于删除对象上的属性。它很像 deleteoperator&#xff0c;但它是一个函数。 Reflect.delet…

Python操作Azure Blob Storage

安装 Azure Storage SDK for Python 最简单的方式是在安装了 python 和 pip 的机器上直接执行下面的命令&#xff1a; pip install azure-storage 安装完成后通过 pip freeze 命令查看安装的版本&#xff1a; 由于 Azure Storage SDK for Python 是一个开源项目&#xff0c;…

Buildroot系列开发(七)block device

摘自&#xff1a;百问网 文章目录1.块设备2.1 什么是块设备&#xff1f;raw flash&#xff1f;2.2 block device 列表2.3 块设备分区2.4 传输数据到块设备2. 块设备文件系统2.1 支持的块设备文件系统2.2 linux / unix 其他日志文件系统2.3 F2FS2.4 SquashFS2.5 如何选择最佳文件…

计算机网络-转发表和路由选择协议

有志者&#xff0c;事竟成 文章目录一、描述1、转发表和路由选择协议二、总结一、描述 1、转发表和路由选择协议 前面我们说过&#xff0c;路由器从与它相连的一条通信链路得到分组&#xff0c;然后向与它相连的另一条通信链路转发该分组。但是路由器怎样决定它应当向哪条链路…

Docker[4]-Docker数据卷

数据卷 前面我们介绍了镜像和容器&#xff0c;通过镜像我们可以启动多个容器&#xff0c;但是我们发现当我们的容器停止获取删除后&#xff0c;我们在容器中的应用的一些数据也丢失了&#xff0c;这时为了解决容器的数据持久化&#xff0c;我们需要通过容器数据卷来解决这个问…

一文4000字教你如何使用可视化的Docker进行UI自动化测试

随着 docker 的发展&#xff0c;很多测试的同学也已经在测试工作上使用 dockr 作为环境基础去进行一些自动化测试&#xff0c;这篇文章主要讲述我们在 docker 中使用浏览器进行自动化测试如果可以实现可视化&#xff0c;同时可以对浏览器进行相关的操作。 开篇 首先我们先了解…

【C++学习笔记】C++编程环境配置

g跟gcc之间是否有依赖关系 g跟gcc之间没有依赖关系&#xff0c;两者分别对应面向C和C语言的编译程序&#xff0c;关于gcc和g的区别&#xff0c;请参考知乎回答《gcc和g是什么关系&#xff1f; ——gcc 和 g 的区别》 1 Ubuntu环境配置 Ubuntu官方源提供gcc和g预编译版本 Ub…

用一张图说一说 ChatGPT 内部技术工作流程

前沿 这几天ChatGPT可谓是热火朝天&#xff0c;很多同事和朋友都来找到勇哥&#xff0c;说能不能说一说相关话题&#xff0c;但是之前几天勇哥都在默默的干一件大事情&#xff0c;今天终于成型、有结果了&#xff0c;所有就抽了点时间来和大家一起聊聊ChatGPT背后的技术&#…

.net开发安卓入门 - 布局与样式(像素单位px、dp、sp的区别)

.net开发安卓入门 - 布局与样式布局LinearLayoutRelativeLayoutTableLayoutRecyclerViewListViewGridViewGridLayoutTabbed Layouts主题 Material Theme主题应用程序主题活动像素pxdpdipsp常用UI框架推荐常用动画推荐布局 布局用于排列构成屏幕的 UI 界面的元素 (&#xff0c;…

没有公网IP,怎样远程查看视频监控?

视频监控通常被称作“第三只眼”。如今&#xff0c;除了最基础的安防需求外&#xff0c;视频监控在不同的应用场景延伸出了各种各样的功能需求&#xff0c;并且正与日俱增。 常见的家庭应用场景&#xff0c;如照看老人小孩、宠物等&#xff1b;常见的公司应用场景&#xff0c;如…

vue的script动态改css、scss变量方法

解决场景&#xff1a;script设颜色变量&#xff0c;<style>的background-color的值"#ddd"的跟着变 序 1、这篇博文适用vue2和vue3版本&#xff0c;博主实验时&#xff0c;vue3的版本是^3.2.45 2、 其实要解决的方案在vue3里有一个专栏“单文件组件的 <…

[附源码]Python计算机毕业设计Django志愿者服务平台

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

3分钟带你重温 SelectDB 产品发布会亮点!

12月8日的 SelectDB 产品发布会圆满举办&#xff0c;一时间吸引了无数业内关注&#xff0c;大家都对这款在正式发布前就拿下 ClickBench 全球第一的云数仓产品充满期待与好奇。万众瞩目下&#xff0c;SelectDB Cloud 终于正式与大家见面了~~ 以下是这场发布会的详细解读&#…

蜂鸟E203学习笔记(五)——执行

1.1 执行概述 1.1.1 指令译码 指令所包含的信息编码在有限长度的指令字中&#xff0c;信息如下&#xff1a; 指令所需要读取的操作数寄存器索引指令需要写回的寄存器索引指令的其他信息如指令类型、指令的操作信息等 顺便注意&#xff1a;并非所有的处理器流水线都会在译码…