一文秒懂 Java Google Guava 实现

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析


阶段4、深入jdk其余源码解析


阶段5、深入jvm源码解析

码哥源码部分

码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】

码哥讲源码【炸雷啦!炸雷啦!黄光头他终于跑路啦!】

码哥讲源码-【jvm课程前置知识及c/c++调试环境搭建】

​​​​​​码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】

码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】

码哥讲源码【你水不是你的错,但是你胡说八道就是你不对了!】

码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】

终结B站没人能讲清楚红黑树的历史,不服等你来踢馆!

打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】   


 是托管在 Github.com 上的流行的 Google 开源的 Java 线程池库。

Guava 包含了许多有用的并发类,同时还包含了几个方便的 ExecutorService 实现,但这些实现类都无法通过直接实例化或子类化来创建实例。取而代之的是提供了 MoreExecutors 助手类来创建它们的实例。

给 Maven 添加 Guava 依赖

为了将 Google Guava 库包含进当前的项目中,需要将下面的依赖项添加到 Maven pom 文件中。

    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>26.0</version>
    </dependency>

你可以在 Maven 中央仓库 中找到最新版本的 Guava 库

直接执行者和直接执行者服务

有时候,我们希望在当前线程或线程池中执行任务,具体在哪里取决于某些条件。这种情况下,你应该会更喜欢使用单个 Executor 接口,且只需切换实现即可。

虽然将当前线程中的任务的 Executor 或 ExecutorService 的提取出来单独实现并不困难,但它仍然需要编写一些样板代码。

值得庆幸的是,Guava 为我们提供了预定义的实例。

下面的范例演示了如何在同一个线程中执行任务。简单起见,提交的任务会将当前线程休眠 500 毫秒并阻塞当前线程,并在执行的调用完成后让结果立即可用

     Executor executor = MoreExecutors.directExecutor();
    
    AtomicBoolean executed = new AtomicBoolean();
    
    executor.execute(() -> {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        executed.set(true);
    });
    
    assertTrue(executed.get());

directExecutor() 方法返回的实例实际上是一个静态单例,因此使用此方法根本不会在对象创建上带来任何开销。

你应该更喜欢使用此方法来访问 MoreExecutors.newDirectExecutorService(),因为该 API 会在每次调用时创建完整的执行程序服务实现。

退出 Executor 服务

另一个常见问题是: 在线程池仍在运行其任务时关闭虚拟机 。即使采用了取消机制,也无法保证任务执行良好,并在执行程序服务 ( Executor )关闭时停止工作。这可能会导致 JVM 在任务继续工作时无限期挂起。

为了解决这个问题,Guava 引入了一系列已经实例化好的执行器 ( Executor ) 服务。它们是守护线程模式,但会与 JVM 一起终止。

这些执行器服务还提供了 Runtime.getRuntime().addShutdownHook() 方法用于添加一个关闭钩子,用于设置 VM 在放弃挂起的任务之前等待一段预配置的超时时间。

下面的示例中,我们提交了一个无限循环的任务,我们使用了包含 100 毫秒超时时间的已经存在的执行程序服务来运行任务,并在超过配置的超时时间之后终止 VM 。如果没有 exitingExecutorService ,此任务将导致 VM 无限期挂起。

    ThreadPoolExecutor executor = 
      (ThreadPoolExecutor) Executors.newFixedThreadPool(5);
    ExecutorService executorService = 
      MoreExecutors.getExitingExecutorService(executor, 
        100, TimeUnit.MILLISECONDS);
    
    executorService.submit(() -> {
        while (true) {
        }
    });

监听装饰器

监听装饰器允许我们封装 ExecutorService 并在提交任务时返回 ListenableFuture 实例而不是简简单单的 Future 实例。

ListenableFuture 接口扩展自 Future 接口,并添加了一个新方法 addListener(),该方法用于添加在将来完成时调用的侦听器。

一般情况下,我们很少直接使用 ListenableFuture.addListener() 方法,而是使用 Futures 类提供的许多辅助方法。例如,通过Futures.allAsList() 方法,我们可以在单个 ListenableFuture 中组合多个 ListenableFuture 实例,并会在这些实例在成功完成后将所有的 futures 合并并返回结果。

    ExecutorService executorService = Executors.newCachedThreadPool();
    ListeningExecutorService listeningExecutorService = 
      MoreExecutors.listeningDecorator(executorService);
    
    ListenableFuture<String> future1 = 
      listeningExecutorService.submit(() -> "简单");
    ListenableFuture<String> future2 = 
      listeningExecutorService.submit(() -> "教程");
    
    String greeting = Futures.allAsList(future1, future2).get()
      .stream()
      .collect(Collectors.joining(""));
    assertEquals("简单教程", greeting);
  • 20
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值