并发下线程池与异步快速入门+demo实战

多线程回顾


什么是线程?

**什么是线程?**操作系统下中每一个运行的进程都包含多个线程的执行,比如打开王者荣耀,你操作英雄的同时,你也可以接收到小学生队友发来的文字消息和听到各种击杀音效,这样一来,你玩王者的同时就可以享受到,视觉,听觉,与小学生交流等多样的游戏体验!
实际上以上的方式都是由多个线程同时协作执行的,多线程的目的就是让我们能够在一个时间点高效的干多件事!!


线程池是什么?项目中为什么一点要使用线程池?

  • 顾名思义,线程池其实就是一个 容纳多个线程的容器 ,其中的线程可以反复使用,省去了频繁创建线程对象的操作 ,

  • 从java虚拟机的层面上来讲,当我们创建一个线程时,都需要尝试在堆区域进行创造对象分配空间,而当系统用户量大时,频繁的创造线程是非常开销大的,甚至都有可能出现OOM的现象!于是使用线程池,应用这种缓存思想,尽量的减少了我们频繁创建线程的开销


多线程的实现方式

多线程:
1)、继承 Thread
2)、实现 Runnable 接口

3)、实现 Callable 接口 + FutureTask (可以拿到返回结果,可以处理异常)

        FutureTask<Integer> futureTask 
        = new FutureTask<>(new MyCallable());
        // 【new FutureTask<>(new MyRunnable(), result)】
        //可以接受runnable的返回值
       new Thread(futureTask).start();

4)、线程池


以上四种方式的对比:

方式 1 和方式 2:主进程无法获取线程的运算结果。不适合当前场景
方式 3:主进程可以获取线程的运算结果,但是不利于控制服务器中的线程资源。可以导致 服务器资源耗尽。
方式 4:通过如下两种方式初始化线程


线程池实战

(将多线程异步任务都交给线程池执行)

// 创建一个线程池,整个系统只有一个
ExecutorService service=Executors.newFiexedThreadPool(3);
// 
service.excute() // 不返回直接执行
service.submit() // 获取任务返回值


//或者
new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit unit, workQueue, threadFactory, 
                       

通过线程池性能稳定,也可以获取执行结果,并捕获异常。但是,在业务复杂情况下,一 个异步调用可能会依赖于另一个异步调用的执行结果。

线程池

一. 线程池的创建

  1. 七大参数
  • corePoolSize 池中一直保持的线程的数量,即使线程空闲。除非设置了 allowCoreThreadTimeOut

  • maximumPoolSize 池中允许的最大的线程数

  • keepAliveTime (释放空闲的线程) 当线程数大于核心线程数的时候,线程在最大多长时间没有接到新任务就会终止释放, 最终线程池维持在 corePoolSize 大小

  • unit 时间单位

  • workQueue
    阻塞队列,用来存储等待执行的任务,如果当前对线程的需求超过了 corePoolSize 大小,就会放在这里等待空闲线程执行

  • threadFactory 创建线程的工厂,比如指定线程名等

  • handler 拒绝策略,如果线程满了,线程池就会使用拒绝策略

工作顺序:

  1. 线程池创建,准备好core数量的核心线程,准备接受任务
  2. core满了,任务进入阻塞队列等待,等core空闲时,从阻塞队列中获取任务到core中执行
  3. 阻塞队列满了,开启新的线程,最大只能到达maximumPoolSize
  4. 线程数大于核心线程数时,空闲线程会在keepAliveTime时间后自动销毁
  5. 线程数到达了max数量,若还有新任务进来执行拒绝策略(handler)默认使用的是丢弃策略AbortPolicy

拒绝策略实现类:

在这里插入图片描述

常见的几种线程池

● newCachedThreadPool
 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若 无可回收,则新建线程。

● newFixedThreadPool
 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
● newScheduledThreadPool
 创建一个定长线程池,支持定时及周期性任务执行。
● newSingleThreadExecutor
 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行


面试题:
一个线程池 core 7; max 20 ,queue:50,100 并发进来怎么分配的;
先有 7 个能直接得到执行,接下来 50 个进入队列排队,在多开 13 个继续执行。现在 70 个
被安排上了。剩下 30 个默认拒绝策略


为什么要使用异步编排:

在这里插入图片描述

异步编排(CompletableFuture ,获取异步结果进行编排)

在 Java 8 中, 新增加了一个包含 50 个方法左右的类: CompletableFuture,提供了非常强大的
Future 的扩展功能,可以帮助我们简化异步编程的复杂性,提供了函数式编程的能力,可以
通过回调的方式处理计算结果,并且提供了转换和组合 CompletableFuture 的方法。


1. 创建异步对象

CompletableFuture 提供四个静态方法来创建一个异步操作 (异步任务有返回值: supplyAsync() 异步回调 )

        CompletableFuture.runAsync(()->{
            System.out.println("当前线程:"+ Thread.currentThread().getId());
            int i=10/2;
            System.out.println("运行结果: "+ i);
        },executor);


2. 计算完成时的回调方法

在这里插入图片描述

   // 异步任务有返回值  CompletableFuture为Future的实现类
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
            return i;
        }, executor).whenComplete((res,exception)->{
            System.out.println("成功完成结果:"+res);
            System.out.println("异常是:"+exception);
        }).exceptionally(throwable -> {
            // 感知异常同时返回自定义信息
            return 10;
        });

        Integer integer = future.get();

        // 5.5.方法执行完成后的处理
        CompletableFuture<Integer> future6 = future3.thenApplyAsync((s -> 1 / 0), executor).handle((result, exception) -> {
            if (exception == null) {
                return result;
            }
            System.out.println("handle处理异常:" + exception);
            return 1;
        });
        System.out.println("handle处理返回结果:" + future6.get());

1、runXxxx 都是没有返回结果的,supplyXxx 都是可以通过future的get获取返回结果的
2、可以传入自定义的线程池,否则就用默认的线程池;
3、handle 方法即可获取到线程操作后的结果和异常,也能进行后续处理,返回自定义的值


3. 线程串行化方法 ( thenRun() )

● Function T:上一个任务返回结果的类型 U:当前任务的返回值类型


        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果: " + i);
            return i;
        }, executor).thenApply((res)->{
            return 22;
        });

        Integer integer = future.get();


        System.out.println("end。。。。。"+integer);

组合执行线程任务

  1. 两任务都执行后再执行的操作

● thenCombine:组合两个 future,获取两个 future 的返回结果,并返回当前任务的返回值
● thenAcceptBoth:组合两个 future,获取两个 future 任务的返回结果,然后处理任务,没有 返回值
● runAfterBoth:组合两个 future,不需要获取 future 的结果,只需两个 future 处理完任务后, 处理该任务


        // 5.6.2.二者都要完成,组合【获取前两个任务返回值,自己无返回值】
        CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1执行");
            return 10 / 2;
        }, executor);
        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2执行");
            return "hello";
        }, executor);
        CompletableFuture<Void> future03 = future01.thenAcceptBothAsync(future02,
                (result1, result2) -> {
                    System.out.println("任务3执行");
                    System.out.println("任务1返回值:" + result1);
                    System.out.println("任务2返回值:" + result2);
                }, executor);
        
        
        // 5.6.1.二者都要完成,组合【不获取前两个任务返回值,且自己无返回值】
        CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务1执行");
            return 10 / 2;
        }, executor);
        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务2执行");
            return "hello";
        }, executor);
        CompletableFuture<Void> future03 = future01.runAfterBothAsync(future02, () -> {
            System.out.println("任务3执行");
        }, executor);


  1. 当两个任务中,任意一个 future 任务完成的时候,执行任务

在这里插入图片描述

● applyToEither:两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值。
● acceptEither:两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值。
● runAfterEither:两个任务有一个执行完成,不需要获取 future 的结果,处理任务,也没有返 回值。


3. 多任务组合
在这里插入图片描述

● allOf:等待所有任务完成
● anyOf:只要有一个任务完成

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java并发与网络编程是当前互联网行业非常热门的技术方向之一。在处理亿级流量的情况下,这些技术更是必不可少的。Java作为一种高性能的编程语言,其在高并发和网络编程方面有着非常丰富的应用经验,因此学习这些知识对于提升自身的技术水平是非常有帮助的。 对于想要深入学习Java并发与网络编程的人来说,《亿级流量Java并发与网络编程实战》这本书是一本非常值得阅读的好书。这本书系统全面地介绍了Java并发编程的基本原理、实战技巧和常见问题解决方案,同时也深入探讨了Java网络编程的相关内容,涵盖了网络通信、Socket编程、NIO与Netty等重要知识。 通过阅读这本书,读者可以了解到Java并发编程中的线程池、锁机制、并发集合等核心知识,还可以学习到如何设计高性能的并发程序以及应对高并发场景下的常见问题。同时,本书也详细介绍了Java网络编程中的各种网络协议、通信模型,以及如何利用Java技术构建高性能的网络应用程序。 总的来说,《亿级流量Java并发与网络编程实战》这本书通过丰富的案例和实战经验,为想要深入学习Java并发与网络编程的读者提供了一本权威、全面的学习指南。阅读本书不仅可以帮助读者系统地理解Java并发与网络编程的知识,还可以帮助他们提升解决实际问题的能力,为今后的技术实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值