zoukankan      html  css  js  c++  java
  • java并发编程之二、分工

    一、Thread Runnable Callable Future FutureTask

    这几个类型是并发任务在java中最基本的映射,Thread以及Runnable以及Callable毋庸赘言了,Future对应的是一个异步任务的引用,可以用来获取一个异步任务的结果,也可以用来判断一个异步任务是否执行结束,还可以用来取消一个异步任务的执行,而FutureTask同时继承了Future和Runnable,所以作为一个工具类,他完全可以用来取代Runnable的使用,而且还更方便。

    二、ThreadPoolExecutor

    虽然我们认为线程是比进程轻量级的东西,但频繁的创建和销毁线程也是非常耗费资源的,所以一般建议在频繁使用线程的地方,尽量使用线程池。在java中可以通过Executors的静态方法来获取相应的线程池,既可以是一般的ExecutorService,也可以是具有定时功能的ScheduledExecutorService,这两个接口都提供了提交异步任务的接口,但隐藏了底层线程池的创建逻辑,但线程池的最优实践一般建议我们自定义自己的线程池,这样你可以更清楚自己所使用的线程池的特性,比如采用何种队列,线程的存在时间,线程的名称等。这里先回顾一下创建线程池的几个核心参数。

    • 构建
      • corePoolSize,线程池的最小线程数,可以评估一个线程池的日常使用的线程数。
      • maximumPoolSize,线程池的最大线程数,假如业务面临一个小高峰,则需要新建线程,但也不能多于这个参数。
      • keepAliveTime&unit,定义当一个线程闲置了多长时间需要回收,比如业务小高峰过去了,不会立刻回收线程,而是需要等待一段时间。
      • workQueue,这个阻塞队列也是很重要的一个参数,采用有界队列还是无界队列,默认的队列很多都是无界队列,如果无限制的加入队列,也会导致OOM等其他问题。
      • threadFactory,通过线程工厂,你可以给线程池创建的线程一些默认的属性,比如线程的名称,有助于后期调试时识别。
      • handler,定义当线程池已满并且队列已满(有界队列)时,如何处理提交的异步任务,包括AbortPolicy(拒绝任务并抛出异常)、CallerRunsPolicy(在调用者自己的线程执行任务)、DiscardOldestPolicy(抛弃最久的任务然后再次尝试提交)和DiscardPolicy(静默抛弃任务)。
    • 异常,线程池异常处理的最佳实践是总是在使用线程池的地方使用try/catch来捕获最多的异常,而不仅仅是依赖线程池自己的异常处理逻辑。

    三、ForkJoinPool

    针对普通的线程池应用,使用ThreadPoolExecutor就可以了,但是如果任务具有分治的特点,则推荐使用ForkJoinPool来提交,他有自己的一套机制,能够更高效的执行任务。

    在ForkJoinPool中一般通过ForkJoinTask来提交任务,而在实现中一般通过ForkJoinTask 的两个抽象子类——RecursiveAction 和 RecursiveTask来构建ForkJoinTask,其中RecursiveAction没有返回值,而RecursiveTask具有返回值,可以根据需要进行选择。

    四、CompletableFuture

    CompletableFuture是在java 1.8中提出的同步转异步的工具类,具有非常强大的表达能力,通过使用CompletableFuture你能够像编写同步代码一样编写异步代码,由于功能强大,所以学习起来有点麻烦,但一旦真的学会了,相信会让你不由得赞叹。需要注意的一点是,CompletableFuture默认使用ForkJoinPool作为线程池,也可以自己提供线程池。

    • 构建,CompletableFuture提供了若干的静态方法,通过静态方法可以很容易的构建相应的实例。
    • 表达,CompletableFuture提供了很多表达语句,汇总之后可以分为下面几类:
      • 串行,主要是 thenApply、thenAccept、thenRun 和 thenCompose 这四个系列的接口,表达的是执行完一个异步任务之后执行下一个异步任务。
      • 汇聚,主要是 thenCombine、thenAcceptBoth 和 runAfterBoth 系列的接口,表达的是两个异步任务执行完之后执行下一个任务。
      • 异或,主要是 applyToEither、acceptEither 和 runAfterEither 系列的接口,表达的是两个异步任务任何一个执行完之后执行下一个任务。
    • 异常,异步编程中无法使用try/catch机制来捕获异常,不过CompletableFuture同样提供了exceptionally、whenComplete和handle三个接口来使用,exceptionally明显是用在异常处理中,而whenComplete相当于语言中的finally,而handle在于whenComplete相同功能的同时支持返回结果。

    五、CompletionService

    CompletionService是Java提供的并发执行的工具类,它解耦了异步任务的提交者和异步任务结果的消费者,也是一种producer-consumer的实现。使用CompletionService的典型场景如下:

    • 批量异步提交,批量异步获取,异步任务的生产者只负责向线程池中提交任务,不负责任务的处理,而异步结果的消费者,可以方便的拿到所有异步任务的结果,并且异步结果的获取严格依赖于异步任务完成的时间,即消费者会按照异步任务的完成时间拿到相应的异步处理结果,这在某些场景下会非常有效。
    • 批量异步提交,获取最快结果,这个场景其实是对上面场景的一个深化,虽然通过CompletionService可以拿到所有的异步结果,但是对于某些操作,可能只需要最快返回的那个,其余的异步操作就可以取消了。比如在服务端同时在几个数据中心进行查询,最先返回的结果会被使用,而其他请求会被取消。
  • 相关阅读:
    Android中Activity之间通信
    vs2017 2019 下载更新慢的解决方法
    c# 判断某个类是否实现某个接口
    mvc api 关于 post 跟get 请求的一些想法[FromUri] 跟[FromBody] 同一个控制器如何实现共存
    vs2017 mvc 自定义路由规则 出现 404.0 错误代码 0x80070002
    C# winform 发布的时候没有app.config去哪儿了?
    安装c#服务
    Type.GetType反射的对象创建Activator.CreateInstance
    c# 谷歌动态口令对接
    asp.net mvc 异步控制器
  • 原文地址:https://www.cnblogs.com/029zz010buct/p/12182078.html
Copyright © 2011-2022 走看看