【系统开发】尚硅谷 - 谷粒商城项目笔记(六):异步线程池

news2024/11/14 6:37:28

文章目录

  • 异步线程池讲解
    • 简单线程池
    • 常见的四种线程池
    • 进阶线程池
    • 为什么使用线程池
    • 异步编排
      • 基本用法
      • 其他API
      • 线程串行化
      • 两任务组合
        • 都完成时
        • 一个完成时
      • 多任务组合


异步线程池讲解

简单线程池

public class Test01 {

    public static void main(String[] args) {

        // 声明一个有10个线程的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);

        // 传入一个Runnable接口,并执行run()方法
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                while (true){
                    System.out.println("线程池内的输出:A");
                }
            }
        });

        while (true){
            System.out.println("线程池外的输出:B");
        }

    }
}

可以看到,控制台输出中,既有A也有B,故实现了异步执行的效果:

image-20220129141637495

常见的四种线程池

image-20220129140332812

进阶线程池

image-20220129134504191

public class Test02 {
    public static void main(String[] args) {

        // 核心线程数,会一直占用在线程池中
        int corePoolSize = 5;
        // 最大线程数(控制资源)
        int maximumPoolSize = 200;
        // 存活时间(单位与unit一致,类型为long)。如果当前线程数大于核心线程数
        long keepAliveTime = 2000L;
        // unit:时间单位 这里使用毫秒
        // MILLISECONDS(毫秒),SECONDS(秒),MINUTES(分钟),HOURS(小时),DAYS(天)
        TimeUnit timeUnit = TimeUnit.MILLISECONDS;
        // 阻塞队列(如果没有空闲线程,且当前线程已经达到max,则进入阻塞队列等待)
        BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<Runnable>(100);
        // threadFactory: 线程的创建工厂
        ThreadFactory defaultThreadFactory = Executors.defaultThreadFactory();
        // handler: 如果阻塞队列满了,则按照我们指定的拒绝策略执行任务
        // 自带的几种拒绝策略:
        // 1. AbortPolicy:当任务添加到线程池中被拒绝时,它将抛出 RejectedExecutionException 异常(拒绝新来的任务,并抛出异常)
        // 2. CallerRunsPolicy:当任务添加到线程池中被拒绝时,会在线程池当前正在运行的Thread线程池中处理被拒绝的任务。(直接允许Run方法,同步调用)
        // 3. DiscardPolicy:当任务添加到线程池中被拒绝时,线程池将丢弃被拒绝的任务。(拒绝新来的任务,但不抛异常)
        // 4. DiscardOldestPolicy:当任务添加到线程池中被拒绝时,线程池会放弃等待队列中最旧的未处理任务,然后将被拒绝的任务添加到等待队列中。(为接收新任务,丢弃最老的任务)
        ThreadPoolExecutor.AbortPolicy abortPolicy = new ThreadPoolExecutor.AbortPolicy();
        // 创建线程池
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                timeUnit,
                blockingQueue,
                defaultThreadFactory,
                abortPolicy);
        // 使用线程池
        threadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {
                while (true){
                    System.out.println("线程池内的输出:A");
                }
            }
        });

        while (true){
            System.out.println("线程池外的输出:B");
        }

    }
}

也可以实现同样的效果,但是比简单的线程池更好的控制了线程资源的使用

image-20220129141936810

为什么使用线程池

image-20220129140412494

异步编排

基本用法

先演示一下正常情况下,CompletableFuture异步编排的效果

public static void main(String[] args) throws ExecutionException, InterruptedException {

        // 首先创建一个线程池,创建方法参照之前的代码,这里直接封装成方法
        ThreadPoolExecutor threadPoolExecutor = createExector();
        // 开始异步编排
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            // 异步任务,相当于run()方法
            System.out.println("当前线程名:" + Thread.currentThread().getName());
            int i = 10 / 2;
            System.out.println("运行结果:" + i);
            return i;
        }, threadPoolExecutor).whenComplete((result, exception) -> {
            // 如果上面的异步任务执行完毕了,就进入这里,传入参数是上面任务的结果result和异常信息exception
            System.out.println("whenComplete中 :异步任务完成了,结果是:" + result + ",异常是:" + exception);
        }).exceptionally(exception -> {
            // 如果发生异常就进入这里,在这里可以对返回结果进行修正,或者手动抛出异常 exception.printStackTrace()
            System.out.println("exceptionally中:发生了异常:" + exception);
            return 10;
        });
        // 获取异步任务结果
        Integer result = future.get();
        System.out.println("main...end..."+result);

    }

image-20220129153001041

有异常的情况,将supplyAsync中的代码修改为如下代码:

// 异步任务,相当于run()方法
System.out.println("当前线程名:" + Thread.currentThread().getName());
int i = 10 / 0;
System.out.println("运行结果:" + i);
return i;

image-20220129153516820

总结:

  1. 首先执行supplyAsync中的代码
  2. supplyAsync中代码执行完毕后(抛出异常也算执行完毕)就进入whenComplete中,whenComplete会获取supplyAsync的结果信息和异常信息
  3. 如果supplyAsync中的代码有异常,则会在whenComplete中的代码执行完之后,进入exceptionally中,exceptionally会获取异常信息,并可以决定是否手动抛出异常 exception.printStackTrace(),还可以手动返回一个默认结果(类似服务降级机制)

其他API

image-20220129153728828

handle方法相当于结合了whenComplete和exceptionally,handle不仅可以获取supplyAsync中的结果,还可以获取异常信息并返回默认结果

handleAsync方法和whenCompleteAsync方法类似,代表其中的代码可能会使用与之前supplyAsync中使用的线程不同的线程执行

image-20220129153803399

使用handle,没有异常的情况:

// 首先创建一个线程池,创建方法参照之前的代码,这里直接封装成方法
ThreadPoolExecutor threadPoolExecutor = createExector();
// 开始异步编排
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
    // 异步任务,相当于run()方法
    System.out.println("当前线程名:" + Thread.currentThread().getName());
    int i = 10 / 2
    System.out.println("运行结果:" + i);
    return i;
}, threadPoolExecutor).handle((result, exception) -> {
    if(exception==null){
        System.out.println("没有发生异常,结果是:" + result);
        return result;
    }else{
        System.out.println("发生了异常:" + exception);
        return 10;
    }
});
// 获取异步任务结果
Integer result = future.get();
System.out.println("main...end..."+result);

image-20220129154538110

使用handle,有异常的情况:

// 制造异常
int i = 10 / 0;

image-20220129154642431

线程串行化

image-20220129155117973

两任务组合

都完成时

两个任务都完成时,才进行下面的操作

image-20220129160240740

image-20220129160309233

runAfterBothAsync():两任务执行完成后再执行,但是不能获取两个任务的执行结果

// 首先创建一个线程池,创建方法参照之前的代码,这里直接封装成方法
ThreadPoolExecutor threadPoolExecutor = createExector();
// 任务1
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
    System.out.println("任务1开始");
    int i = 10/2;
    System.out.println("任务1结束");
    return i;
},threadPoolExecutor);
// 任务2
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
    System.out.println("任务2开始");
    int j = 18/3;
    System.out.println("任务2结束");
    return j;
},threadPoolExecutor);
// 两任务组合
future1.runAfterBothAsync(future2,()->{
    System.out.println("两任务组合...");
},threadPoolExecutor);

image-20220129163911319

thenAcceptBothAsync():可以接收到两个任务执行完之后的结果信息

// 首先创建一个线程池,创建方法参照之前的代码,这里直接封装成方法
ThreadPoolExecutor threadPoolExecutor = createExector();
// 任务1
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
    System.out.println("任务1开始");
    int i = 10/2;
    System.out.println("任务1结束");
    return i;
},threadPoolExecutor);
// 任务2
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
    System.out.println("任务2开始");
    int j = 18/3;
    System.out.println("任务2结束");
    return j;
},threadPoolExecutor);
// 两任务组合
future1.thenAcceptBothAsync(future2,(f1,f2)->{
    System.out.printf("之前的结果:f1 = %d,f2 = %d\n",f1,f2);
},threadPoolExecutor);

image-20220129164300812

thenCombineAsync():不仅可以获取两个任务的结果,还可以return合并后任务的返回值

// 首先创建一个线程池,创建方法参照之前的代码,这里直接封装成方法
ThreadPoolExecutor threadPoolExecutor = createExector();
// 任务1
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
    System.out.println("任务1开始");
    int i = 10/2;
    System.out.println("任务1结束");
    return i;
},threadPoolExecutor);
// 任务2
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
    System.out.println("任务2开始");
    int j = 18/3;
    System.out.println("任务2结束");
    return j;
},threadPoolExecutor);
// 两任务组合
CompletableFuture<String> future3 = future1.thenCombineAsync(future2, (f1, f2) -> {
    return f1 + " -> " + f2;
}, threadPoolExecutor);

System.out.println(future3.get());

image-20220129164527438

一个完成时

两个任务中,只要有一个完成,就可以进行下面的操作

image-20220129164808629

image-20220129164833959

runAfterEitherAsync():无传入参数,无返回值

// 首先创建一个线程池,创建方法参照之前的代码,这里直接封装成方法
ThreadPoolExecutor threadPoolExecutor = createExector();
// 任务1
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
    System.out.println("任务1开始");
    int i = 10/2;
    System.out.println("任务1结束");
    return i;
},threadPoolExecutor);
// 任务2
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
    System.out.println("任务2开始");
    int j = 18/3;
    try {
        // 让任务2延迟3秒
        Thread.sleep(3000L);
        System.out.println("任务2结束");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return j;
},threadPoolExecutor);
// 两任务只要有一个完成,就执行任务3
future1.runAfterEitherAsync(future2,()->{
    System.out.println("任务3执行...");
},threadPoolExecutor);

image-20220129165559898

acceptEitherAsync():有传入参数,无返回结果

 // 首先创建一个线程池,创建方法参照之前的代码,这里直接封装成方法
ThreadPoolExecutor threadPoolExecutor = createExector();
// 任务1
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
    System.out.println("任务1开始");
    int i = 10/2;
    System.out.println("任务1结束");
    return i;
},threadPoolExecutor);
// 任务2
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
    System.out.println("任务2开始");
    int j = 18/3;
    try {
        // 让任务2延迟3秒
        Thread.sleep(3000L);
        System.out.println("任务2结束");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return j;
},threadPoolExecutor);
// 两任务只要有一个完成,就执行任务3
future1.acceptEitherAsync(future2,(result)->{
    System.out.println("任务3执行:"+result);
},threadPoolExecutor);

image-20220129165915557

applyToEitherAsync():有传入参数,有返回值

// 首先创建一个线程池,创建方法参照之前的代码,这里直接封装成方法
ThreadPoolExecutor threadPoolExecutor = createExector();
// 任务1
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
    System.out.println("任务1开始");
    int i = 10/2;
    System.out.println("任务1结束");
    return i;
},threadPoolExecutor);
// 任务2
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
    System.out.println("任务2开始");
    int j = 18/3;
    try {
        // 让任务2延迟3秒
        Thread.sleep(3000L);
        System.out.println("任务2结束");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return j;
},threadPoolExecutor);
// 两任务只要有一个完成,就执行任务3
CompletableFuture<String> future3 = future1.applyToEitherAsync(future2, (result) -> {
    return "之前的结果是:" + result;
}, threadPoolExecutor);
System.out.println("任务3的结果是:"+future3.get());

image-20220129170133732

多任务组合

allOf():所有任务执行完,才进行下面的操作

// 首先创建一个线程池,创建方法参照之前的代码,这里直接封装成方法
ThreadPoolExecutor threadPoolExecutor = createExector();
// 任务1
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
    System.out.println("任务1开始");
    int i = 10/2;
    System.out.println("任务1结束");
    return i;
},threadPoolExecutor);
// 任务2
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
    System.out.println("任务2开始");
    int i = 21 / 3;
    System.out.println("任务2结束");
    return i;
}, threadPoolExecutor);
// 任务3
CompletableFuture<Integer> future3 = CompletableFuture.supplyAsync(() -> {
    System.out.println("任务3开始");
    int j = 18/3;
    try {
        // 让任务2延迟3秒
        Thread.sleep(3000L);
        System.out.println("任务3结束");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return j;
},threadPoolExecutor);
// 所有任务都执行完成,才进行下面的操作
CompletableFuture<Void> allOf = CompletableFuture.allOf(future1, future2, future3);
// 阻塞等待所有任务都执行完成,这句话必须要加,否则起不到阻塞等待所有任务完成的作用
allOf.get();
// 输出结果
System.out.printf("任务1结果:%d,任务2结果:%d,任务3结果:%d\n",future1.get(),future2.get(),future3.get());

image-20220129171504873

anyOf():只要有一个任务完成,就可以执行下面的操作

// 首先创建一个线程池,创建方法参照之前的代码,这里直接封装成方法
ThreadPoolExecutor threadPoolExecutor = createExector();
// 任务1
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
    System.out.println("任务1开始");
    int i = 10/2;
    System.out.println("任务1结束");
    return i;
},threadPoolExecutor);
// 任务2
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
    System.out.println("任务2开始");
    int i = 21 / 3;
    System.out.println("任务2结束");
    return i;
}, threadPoolExecutor);
// 任务3
CompletableFuture<Integer> future3 = CompletableFuture.supplyAsync(() -> {
    System.out.println("任务3开始");
    int j = 18/3;
    try {
        // 让任务2延迟3秒
        Thread.sleep(3000L);
        System.out.println("任务3结束");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return j;
},threadPoolExecutor);
// 只要有一个任务执行完成,就可以进行下面的操作
CompletableFuture<Object> anyOf = CompletableFuture.anyOf(future1, future2, future3);
// 阻塞等待至少有一个任务执行完成
anyOf.get();
// 输出结果
System.out.printf("首先完成的任务的结果是:%d\n",anyOf.get());

image-20220129171934099

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

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

相关文章

Java——集合

文章目录 1、集合概述2、集合类体系结构Collection集合体系 3、Collection集合常用API3、Collection集合的遍历方式方式一&#xff1a;迭代器方式二&#xff1a;foreach/增强for循环方式三&#xff1a;lambda表达式 4、List系列集合List集合特点和特有APILinkedList集合 5、集合…

物流园仓库智能综合监控系统

现代经济的不断发展&#xff0c;仓储物流业也在快速地发展&#xff0c;物流仓库作为物质资源的存储和转运&#xff0c;在经济生产中发挥着重大的作用&#xff0c;但是在此期间&#xff0c;随之而来的是物品丢失、被盗、损坏等一系列安全隐患事件。 物流仓库里面存储物品的多数都…

nginx: client intended to send too large body

最近上传大于1M文件的时候&#xff0c;报错nginx。 413 Request Entity Too Large 经过排查修改nginx配置 这是最简单的一个做法&#xff0c;着报错原因是nginx不允许上传配置过大的文件&#xff0c;那么件把nginx的上传大小配置调高就好。 1、打开nginx主配置文件nginx.co…

【性能测试】loadrunner12.55教程(一)--知识准备

目录 1.0. 前言 1.1 性能测试术语介绍 1.1.1 响应时间&#xff08;Response time&#xff09; 1.1.2 并发用户数 1.1.3 吞吐量&#xff08;Throughput&#xff09; 1.1.4 吞吐率&#xff08;Throughout&#xff09; 1.1.5 TPS&#xff08;Transaction Per Second&#x…

深度复盘:那些曾在618一鸣惊人的新品牌,今天过得怎么样?

分析师&#xff1a;yolo 编辑&#xff1a;yolo 出品&#xff1a;增长黑盒研究组 *本报告为增长黑盒独立研究系列&#xff0c; 与第三方不存在任何利益关系 从各平台的活动力度上来看&#xff0c;这届618堪称“史上最卷”&#xff1a;不装了&#xff0c;直接摊牌降价促销。 然而…

《VisualGLM-6B的原理与微调》资料学习分享

清华大学在发布chatGLM-6B后很快速的时间内就又发布了VisualGLM-6B模型&#xff0c;不可谓不强大&#xff0c;VisualGLM-6B官方项目地址在这里&#xff0c;如下所示&#xff1a; VisualGLM-6B 是一个开源的&#xff0c;支持图像、中文和英文的多模态对话语言模型&#xff0c;语…

2022前端趋势报告(上)

前端博主&#xff0c;热衷各种前端向的骚操作&#xff0c;经常想到哪就写到哪&#xff0c;如果有感兴趣的技术和前端效果可以留言&#xff5e;博主看到后会去代替大家踩坑的&#xff5e; 主页: oliver尹的主页 格言: 跌倒了爬起来就好&#xff5e; 一、前言 本文内容来自于《St…

N卡几千块的“智商税”,这下终于要没了

关于 CPU 显卡搭配&#xff0c;有句话大家肯定听过&#xff1a;「 i卡配iU、A卡配AU、N卡配 Fxxk U」 。 小白不要误会&#xff0c;这句话只是大家在喷N卡的定价问题。 拿刚刚过去的剁手节对比&#xff0c;AMD 这边旗舰显卡 RX 7900XT、XTX 价格直接跌到了 5/6000 出头。 而 …

Jenkins集成SonarQube代码质量检测

上一篇文章> Jenkins发布Kubernetes(K8s)集群(基于containerd) 一、SonarQube简介 1、简介 SonarQube是管理代码质量一个开放平台&#xff0c;可以快速的定位代码中潜在的或者明显的错误 2、下载 https://www.sonarsource.com/products/sonarqube/downloads/ 二、实验环境…

Spring Boot请求处理-常用参数注解

PathVariable 路径变量RequestParam 获取请求参数RequestHeader 获取请求头RequestBody 获取请求体【Post】CookieValue 获取Cookie值RequestAttribute 获取request域属性ModelAttribute 1. PathVariable 该注解主要用于rest风格的搭配使用&#xff0c;请求路径中不再以k:v的…

软考高级系统架构设计师(四) 计算机网络2磁盘阵列

目录 磁盘阵列RAID RAID级别 ​IPV6 网络接入技术 综合布线 磁盘阵列RAID 磁盘阵列&#xff08;Redundant Arrays of Independent Disks&#xff0c;RAID&#xff09;&#xff0c;有"数块独立磁盘构成具有冗余能力的阵列”之意。 磁盘阵列是由很多块独立的磁盘&#…

全新形态骨传导,久戴不疼,南卡OE骨传导耳机

随着生活品质的提高&#xff0c;科技的发展&#xff0c;人们对于日常用的耳机可以说是要求越来越高&#xff0c;越来越挑剔了。从耳机的外在设计&#xff0c;内在音质&#xff0c;佩戴的舒适及安全性上都有更高的追求。当然&#xff0c;耳机的设计者们也不遗余力的发挥着他们的…

华为OD机试真题 JavaScript 实现【高矮个子排队】【2023Q2 100分】,附详细解题思路

一、题目描述 现在有一队小朋友&#xff0c;他们高矮不同&#xff0c;我们以正整数数组表示这一队小朋友的身高&#xff0c;如数组{5,3,1,2,3}。 我们现在希望小朋友排队&#xff0c;以“高”“矮”“高”“矮”顺序排列&#xff0c;每一个“高”位置的小朋友要比相邻的位置高…

PHP学习笔记第四天

前言 作者简介&#xff1a;不知名白帽&#xff0c;网络安全学习者。 博客主页&#xff1a;不知名白帽的博客_CSDN博客-网络安全,CTF,内网渗透领域博主 网络安全交流社区&#xff1a;https://bbs.csdn.net/forums/angluoanquan 目录 PHP超级全局变量 PHP $_GLOBALS PHP $_SER…

在 Navicat Premium 中管理 MySQL 用户 | 第 3 部分:配置用户权限

第 3 部分&#xff1a;配置用户权限 在本系列中&#xff0c;我们一直在探索如何使用 Navicat 的旗舰产品 Navicat Premium 执行常见的用户管理任务。在 第 1 部分 中&#xff0c;我们学习了如何使用 Navicat Premium 用户管理工具保护 MySQL root 帐号。而 第 2 部分 重点介绍…

csrf入门

一.CSRF是什么&#xff1f; CSRF&#xff08;Cross-site request forgery&#xff09;&#xff0c;中文名称&#xff1a;跨站请求伪造&#xff0c;也被称为&#xff1a;one click attack/session riding&#xff0c;缩写为&#xff1a;CSRF/XSRF。 二.CSRF可以做什么&#xff…

uniapp webview H5跳转微信小程序

第一步&#xff1a;manifest.json 第二步&#xff1a;index.html <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"utf-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><title>…

Unity编辑器扩展-第六集-创建窗口/批量填图

第五集链接&#xff1a;Unity编辑器扩展-第五集-撤回操作/禁止操作/加快捷键_菌菌巧乐兹的博客-CSDN博客 一、本节目标效果展示 1.创建窗口 2.图片批量赋值到物体上 二、创建窗口 这个功能其实也很好理解&#xff0c;我们之前学了点击选择&#xff0c;但我们难免会遇见需要…

python学习——Matplotlib数据可视化基础

目录 Matplotlib数据可视化基础1.基础语法与折线图rc参数调整中文显示的问题 2.散点图3.条形图案例一&#xff1a;横向条形图案例二&#xff1a;多个条形图案例三&#xff1a;最后一个刻度 4.直方图实例1 频率分布直方图和频数分布直方图 5.饼图6.箱线图综合案例&#xff1a;直…