眼镜网站怎么做,尚海整装官网门店电话,新泰市住房和城乡建设局网站,软件工程学科评估文章目录 一、google-guava工具包简介1、概述2、引包 二、常用工具类1、LoadingCache 缓存2、RateLimiter限流器3、EventBus事件总线#xff08;1#xff09;基本使用#xff08;2#xff09;多消费者#xff08;3#xff09;DeadEvent#xff08;4#xff09;AsyncEve… 文章目录 一、google-guava工具包简介1、概述2、引包 二、常用工具类1、LoadingCache 缓存2、RateLimiter限流器3、EventBus事件总线1基本使用2多消费者3DeadEvent4AsyncEventBus异步消费 参考资料 一、google-guava工具包简介
1、概述
Guava项目包含我们在基于Java的项目中所依赖的几个Google核心库:集合、缓存、原语支持、并发库、公共注释、字符串处理、I/O等等。这些工具中的每一个都被谷歌员工在生产服务中每天使用也被许多其他公司广泛使用。
2、引包
想要使用guava很简单只需要引入依赖包就可以使用了
!-- maven --
!-- https://mvnrepository.com/artifact/com.google.guava/guava --
dependencygroupIdcom.google.guava/groupIdartifactIdguava/artifactIdversion32.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) {RemovalListenerString, String removalListener new RemovalListenerString, String() {public void onRemoval(RemovalNotificationString, String removal) {System.out.println(移出了key removal.getKey());System.out.println(移出了key removal.getCause());System.out.println(移出了key removal.getValue());}};// 定义缓存key-value的形式LoadingCacheString, String caches CacheBuilder.newBuilder()// 缓存最大值超过最大值会移出.maximumSize(10)// 自上次读取或写入时间开始10分钟过期.expireAfterAccess(10, TimeUnit.MINUTES)// 自上次写入时间开始10分钟过期.expireAfterWrite(10, TimeUnit.MINUTES)// 基于权重驱逐key.maximumWeight(100000).weigher(new WeigherString, String() {public int weigh(String k, String v) {// 获取权重return v.getBytes().length;}})// 设置移出监听器同步的高并发可能会阻塞.removalListener(removalListener)// 构造获取缓存数据的方法.build(new CacheLoaderString, 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 CallableString() {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);
//每秒限流 permitsPerSecondwarmupPeriod 则是数据初始预热时间从第一次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 3DeadEvent
/*** 如果没有消息订阅者监听消息 EventBus将发送DeadEvent消息*/
public static class DeadEventListener {// 消息类型必须是DeadEventSubscribepublic 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{sourceEventBus{test}, event123.12} 4AsyncEventBus异步消费
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