google-guava工具包常用工具类详解(持续更新)

文章目录

  • 一、google-guava工具包简介
    • 1、概述
    • 2、引包
  • 二、常用工具类
    • 1、LoadingCache 缓存
    • 2、RateLimiter限流器
    • 3、EventBus事件总线
      • (1)基本使用
      • (2)多消费者
      • (3)DeadEvent
      • (4)AsyncEventBus异步消费
  • 参考资料

一、google-guava工具包简介

1、概述

Guava项目包含我们在基于Java的项目中所依赖的几个Google核心库:集合、缓存、原语支持、并发库、公共注释、字符串处理、I/O等等。这些工具中的每一个都被谷歌员工在生产服务中每天使用,也被许多其他公司广泛使用。

2、引包

想要使用guava很简单,只需要引入依赖包就可以使用了:

<!-- maven -->
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>32.1.3-jre</version>
</dependency>
// gradle
// https://mvnrepository.com/artifact/com.google.guava/guava
implementation group: 'com.google.guava', name: 'guava', version: '32.1.3-jre'

二、常用工具类

1、LoadingCache 缓存

LoadingCache 在实际场景中有着非常广泛的使用,通常情况下如果遇到需要大量时间计算或者缓存值的场景,就应当将值保存到缓存中。LoadingCache 和 ConcurrentMap 类似,但又不尽相同。

最大的不同是 ConcurrentMap 会永久的存储所有的元素值直到他们被显示的移除,但是 LoadingCache 会为了保持内存使用合理会根据配置自动将过期值移除。

import com.google.common.cache.*;import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;public class CacheMain {public static void main(String[] args) {RemovalListener<String, String> removalListener = new RemovalListener<String, String>() {public void onRemoval(RemovalNotification<String, String> removal) {System.out.println("移出了key:" + removal.getKey());System.out.println("移出了key:" + removal.getCause());System.out.println("移出了key:" + removal.getValue());}};// 定义缓存,key-value的形式LoadingCache<String, String> caches = CacheBuilder.newBuilder()// 缓存最大值,超过最大值会移出.maximumSize(10)// 自上次读取或写入时间开始,10分钟过期.expireAfterAccess(10, TimeUnit.MINUTES)// 自上次写入时间开始,10分钟过期.expireAfterWrite(10, TimeUnit.MINUTES)// 基于权重驱逐key.maximumWeight(100000).weigher(new Weigher<String, String>() {public int weigh(String k, String v) {// 获取权重return v.getBytes().length;}})// 设置移出监听器(同步的,高并发可能会阻塞).removalListener(removalListener)// 构造获取缓存数据的方法.build(new CacheLoader<String, String>() {public String load(String key) {return createValue(key);}});// 需要检查异常try {System.out.println(caches.get("key"));} catch (ExecutionException e) {e.printStackTrace();}// 不会检查异常caches.getUnchecked("key");caches.getIfPresent("key");// 使用Callable,将call()方法的返回值作为缓存try {System.out.println(caches.get("ckey", new Callable<String>() {@Overridepublic String call() throws Exception {return "Callable";}})); // CallableSystem.out.println(caches.get("ckey")); // Callable} catch (ExecutionException e) {e.printStackTrace();}// 直接放缓存caches.put("key2", "v2");// 将缓存作为ConcurrentMap输出System.out.println(caches.asMap());// 删除keycaches.invalidate("key");caches.invalidateAll(Arrays.asList("key", "key1"));caches.invalidateAll();// 清除过期缓存,一般在写入的时候才会清理部分缓存,如果需要,可以手动清除一下caches.cleanUp();}private static String createValue(String key) {System.out.println("获取value");return "value";}
}

2、RateLimiter限流器

常用方法:

/**
* 创建一个稳定输出令牌的RateLimiter,保证了平均每秒不超过permitsPerSecond个请求
* 当请求到来的速度超过了permitsPerSecond,保证每秒只处理permitsPerSecond个请求
* 当这个RateLimiter使用不足(即请求到来速度小于permitsPerSecond),会囤积最多permitsPerSecond个请求
*/
public static RateLimiter create(double permitsPerSecond) 
/**
* 创建一个稳定输出令牌的RateLimiter,保证了平均每秒不超过permitsPerSecond个请求
* 还包含一个热身期(warmup period),热身期内,RateLimiter会平滑的将其释放令牌的速率加大,直到起达到最大速率
* 同样,如果RateLimiter在热身期没有足够的请求(unused),则起速率会逐渐降低到冷却状态
* 
* 设计这个的意图是为了满足那种资源提供方需要热身时间,而不是每次访问都能提供稳定速率的服务的情况(比如带缓存服务,需要定期刷新缓存的)
* 参数warmupPeriod和unit决定了其从冷却状态到达最大速率的时间
*/
public static RateLimiter create(double permitsPerSecond, long warmupPeriod, TimeUnit unit);
//每秒限流 permitsPerSecond,warmupPeriod 则是数据初始预热时间,从第一次acquire 或 tryAcquire 执行开时计算
public static RateLimiter create(double permitsPerSecond, Duration warmupPeriod)
//获取一个令牌,阻塞,返回阻塞时间
public double acquire()
//获取 permits 个令牌,阻塞,返回阻塞时间
public double acquire(int permits)
// 获取一个令牌,如果获取不到立马返回false
public boolean tryAcquire()
//获取一个令牌,超时返回
public boolean tryAcquire(Duration timeout)
获取 permits 个令牌,超时返回
public boolean tryAcquire(int permits, Duration timeout)
RateLimiter limiter = RateLimiter.create(2, 3, TimeUnit.SECONDS);
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
---------------  结果 -------------------------
get one permit cost time: 0.0s
get one permit cost time: 1.331672s
get one permit cost time: 0.998392s
get one permit cost time: 0.666014s
get one permit cost time: 0.498514s
get one permit cost time: 0.498918s
get one permit cost time: 0.499151s
get one permit cost time: 0.488548s

因为RateLimiter滞后处理的,所以第一次无论取多少都是零秒
可以看到前四次的acquire,花了三秒时间去预热数据,在第五次到第八次的acquire耗时趋于平滑

3、EventBus事件总线

EventBus是Guava的事件处理机制,是设计模式中的观察者模式(生产/消费者编程模型)的优雅实现。对于事件监听和发布订阅模式,EventBus是一个非常优雅和简单解决方案,我们不用创建复杂的类和接口层次结构。

(1)基本使用

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;public class EventBusMain {/*** 定义消息实体,EventBus只支持一个消息参数,多个参数需要自己封装为对象*/public static class MyEvent {private String message;public MyEvent(String message) {this.message = message;}public String getMessage() {return message;}}/*** 定义消费者*/public static class EventListener {// 使用@Subscribe 可以监听消息@Subscribepublic void handler(MyEvent event) {System.out.println("消费者接收到消息:" + event.getMessage());}}public static void main(String[] args) {// 定义EventBusEventBus eventBus = new EventBus("test");// 注册消费者EventListener listener = new EventListener();eventBus.register(listener);// 发送消息eventBus.post(new MyEvent("消息1"));eventBus.post(new MyEvent("消息2"));eventBus.post(new MyEvent("消息3"));}
}

结果:
消费者接收到消息:消息1
消费者接收到消息:消息2
消费者接收到消息:消息3

(2)多消费者

在消费者的方法中,会自动根据参数的类型,进行消息的处理。

/*** 定义消费者*/
public static class EventListener {// 使用@Subscribe 可以监听消息@Subscribepublic void handler1(MyEvent event) {System.out.println("消费者接收到MyEvent1消息:" + event.getMessage());}@Subscribepublic void handler2(MyEvent event) {System.out.println("消费者接收到MyEvent2消息:" + event.getMessage());}@Subscribepublic void handler3(String event) {System.out.println("消费者接收到String消息:" + event);}@Subscribepublic void handler4(Integer event) {System.out.println("消费者接收到Integer消息:" + event);}}public static void main(String[] args) {// 定义EventBusEventBus eventBus = new EventBus("test");// 注册消费者EventListener listener = new EventListener();eventBus.register(listener);// 发送消息eventBus.post(new MyEvent("消息1"));eventBus.post("消息2");eventBus.post(99988);
}

结果:
消费者接收到MyEvent2消息:消息1
消费者接收到MyEvent1消息:消息1
消费者接收到String消息:消息2
消费者接收到Integer消息:99988

(3)DeadEvent

/*** 如果没有消息订阅者监听消息, EventBus将发送DeadEvent消息*/
public static class DeadEventListener {// 消息类型必须是DeadEvent@Subscribepublic void listen(DeadEvent event) {System.out.println(event);}
}public static void main(String[] args) {// 定义EventBusEventBus eventBus = new EventBus("test");// 注册消费者EventListener listener = new EventListener();eventBus.register(listener);eventBus.register(new DeadEventListener()); // 注册DeadEventListener// 发送消息eventBus.post(new MyEvent("消息1"));eventBus.post("消息2");eventBus.post(99988);eventBus.post(123.12D); // 如果发送的消息,没有消费者,就会到DeadEvent
}

执行结果
消费者接收到MyEvent2消息:消息1
消费者接收到MyEvent1消息:消息1
消费者接收到String消息:消息2
消费者接收到Integer消息:99988
DeadEvent{source=EventBus{test}, event=123.12}

(4)AsyncEventBus异步消费

import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.Subscribe;import java.util.concurrent.Executors;public class EventBusMain2 {/*** 定义消费者*/public static class EventListener {// 使用@Subscribe 可以监听消息@Subscribepublic void handler1(String event) {System.out.println("消费者1接收到String消息:" + event + ",线程号:" + Thread.currentThread().getId());}@Subscribepublic void handler2(String event) {System.out.println("消费者2接收到String消息:" + event + ",线程号:" + Thread.currentThread().getId());}}public static void main(String[] args) {// 定义EventBus,消费者消费是异步消费AsyncEventBus eventBus = new AsyncEventBus("test", Executors.newFixedThreadPool(10));// 注册消费者EventListener listener = new EventListener();eventBus.register(listener);// 发送消息System.out.println("发送消息,线程号:" + Thread.currentThread().getId());eventBus.post("消息2");}
}

执行结果:
发送消息,线程号:1
消费者2接收到String消息:消息2,线程号:21
消费者1接收到String消息:消息2,线程号:22

参考资料

https://www.cnblogs.com/guanbin-529/p/13022610.html

官网:https://github.com/google/guava
官方文档:https://github.com/google/guava/wiki

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

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

相关文章

电子学会C/C++编程等级考试2023年03月(五级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:拼点游戏 C和S两位同学一起玩拼点游戏。有一堆白色卡牌和一堆蓝色卡牌,每张卡牌上写了一个整数点数。C随机抽取n张白色卡牌,S随机抽取n张蓝色卡牌,他们进行n回合拼点,每次两人各出一张卡牌,点数大者获得三颗巧克力,小者获…

Flutter:web项目跨域问题解决

前后端解决系列 文章目录 一、Flutter web客户端解决本地环境调试跨域问题二、Flutter web客户端解决线上环境跨域问题 一、Flutter web客户端解决本地环境调试跨域问题 就一句命令【--web-browser-flag "--disable-web-security"】&#xff0c;用来屏蔽浏览器域名请…

大模型时代-让AI自己开发自己

一、前言 AI能自己开发自己或者开发和一个很像自己的东西吗&#xff1f;显然是可以的&#xff01;因为AI模型的算法&#xff0c;基本就是学习和递归 二、大模型的算法实现例子 本例子就是通过AI模型来写 大模型的实现通常涉及到深度学习框架和大量的计算资源。具体的算法代…

AI元素深化人类发展之路:挑战与趋势

AI元素深化人类发展之路&#xff1a;挑战与趋势 前言&#xff1a;1.AI元素推动人类发展的方面&#xff1a;2.AI元素引发的挑战与焦虑&#xff1a;3.人类与AI的未来趋势&#xff1a; 前言&#xff1a; 随着AI技术的迅猛发展&#xff0c;人工智能的各种元素逐渐融入我们的生活&a…

elasticsearch和springboot对应版本

网上找了半天没找到&#xff0c;最后还是得上官网找 https://docs.spring.io/spring-data/elasticsearch/reference/elasticsearch/versions.html Spring Data Release TrainSpring Data ElasticsearchElasticsearchSpring FrameworkSpring Boot 2023.1 (Vaughan) 5.2.x 8.…

Java入门学习笔记二

一、抽象类 当编写一个类时&#xff0c;我们往往会为该类定义一些方法&#xff0c;这些方法是用来描述该类的行为方式&#xff0c;那么这些方法都有具体的方法体。 分析事物时&#xff0c;发现了共性内容&#xff0c;就出现向上抽取。会有这样一种特殊情况&#xff0c;就是功…

Python实现高效摸鱼,批量识别银行卡号并自动写入Excel表格

前言 每当有新员工入职&#xff0c;人事小姐姐都要收集大量的工资卡信息&#xff0c;并且生成Excel文档&#xff0c;看到小姐姐这么辛苦&#xff0c;我就忍不住要去帮她了… 于是我用1行代码就实现了自动识别银行卡信息并且自动生成Excel文件&#xff0c;小姐姐当场就亮眼汪汪…

智能冶钢厂环境监控与设备控制系统(边缘物联网网关)

目录 1、项目背景 2、项目功能介绍 3、模块框架 3.1 架构框图 3.2 架构介绍 4、系统组成与工作原理 4.1 数据采集 4.2 指令控制 4.3 其他模块 4.3.1 网页、qt视频流 4.3.2 qt搜索进程 5、成果呈现 6、问题解决 7、项目总结 1、项目背景 这个项目的背景是钢铁行业的…

tesseract-ocr安装使用

描述&#xff1a; 在centos上安装 tesseract 并在springboot项目中使用 步骤一&#xff1a;安装 确认使用的版本tesseract和test4j版本需要匹配&#xff0c;这里选择最新版 tesseract5.3.3 &#xff0c;test4j 5.9.0 版本匹配可查看 Releases nguyenq/tess4j GitHub 或…

Mybatis之缓存

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

使用 iperf 和 iftop 测试网络带宽

博主历时三年精心创作的《大数据平台架构与原型实现&#xff1a;数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行&#xff0c;点击《重磅推荐&#xff1a;建大数据平台太难了&#xff01;给我发个工程原型吧&#xff01;》了解图书详情&#xff0c;…

CSS中神奇的filter属性

CSS是Web开发中不可或缺的一部分&#xff0c;它可以帮助开发者在页面上添加各种各样的样式和效果。其中一个比较神奇的CSS属性就是filter&#xff0c;它可以让我们实现各种有趣的图形处理效果。 一、filter属性的基础 filter属性是CSS中用于对元素进行图形效果处理的属性之一…

C语言—每日选择题—Day47

第一题 1. 以下逗号表达式的值为&#xff08;&#xff09; (x 4 * 5, x * 5), x 25 A&#xff1a;25 B&#xff1a;20 C&#xff1a;100 D&#xff1a;45 答案及解析 D 本题考查的就是逗号表达式&#xff0c;逗号表达式是依次计算每个表达式&#xff0c;但是只输出最后一个表…

【算法题】开源项目热度榜单(js)

解法 const lines ["4","8 6 2 8 6","camila 66 70 46 158 80","victoria 94 76 86 189 211","athony 29 17 83 21 48","emily 53 97 1 19 218", ]; const lines2 ["5","5 6 6 1 2","…

CSS BFC详解

概念 BFC&#xff08;Block Formatting Context&#xff09;是CSS中的一个概念&#xff0c;用于描述一个独立的渲染区域&#xff0c;其中的元素按照一定规则进行布局和渲染。 BFC具有以下特性和作用 清除浮动&#xff1a;当一个元素的float属性设置为left或right时&#xff…

ArkTS入门

代码结构分析 struct Index{ } 「自定义组件&#xff1a;可复用的UI单元」 xxx 「装饰器&#xff1a;用来装饰类结构、方法、变量」 Entry 标记当前组件是入口组件&#xff08;该组件可被独立访问&#xff0c;通俗来讲&#xff1a;它自己就是一个页面&#xff09;Component 用…

运维开发实践 - Kubernetes - 用户权限管控

1.背景 当我们有一个k8s 集群&#xff0c;并且需要将该集群提供给用户使用的时候&#xff0c;我们当然只希望用户只能操作我们预先定义好的资源&#xff0c;即权限管控&#xff0c;RBAC 2. 介绍 Kubernetes中有2种权限管控&#xff0c;一种是为Pod中的应用提供权限管理&…

tuxera2023破解版免费下载 NTFS for Mac读写工具(附序列号)

Tuxera ntfs 2023 破解安装包是一个mac读写ntfs磁盘工具允许您访问&#xff0c;它允许您访问NFTS 驱动器上的文件。 该应用程序提供访问访问Mac 设备中NFTS 格式文件的驱动力&#xff0c;因此您有权基于格式文件进行无困难的访问Windows 数据。 在发生电力灾难或断电时使用防损…

协议到底是什么?

一、为什么需要协议呢&#xff1f; 我们都知道在计算机的世界里只有0和1&#xff0c;那么计算机是怎么从一堆1、0组成的数据中识别出特定的内容的呢&#xff1f;这就需要使用到协议。协议是指两台或者多台设备之间进行通信所必须共同遵守的规定或规则&#xff0c;可以形象的理解…

Signal EM的流程与分析

RedhawkTM 提供了一种在设计中分析Power EM和SignalEM的单一平台方法。Power EM通常作为Static IR和Dynamic IR分析的组成部分进行。Signal EM分析是单独进行分析的,检查设计中所有信号线和过孔的平均(单向或双向)、RMS和峰值电流密度【1】。 1 SignalEM 流程介绍 如图7…