一.Caffeine 原理
1.1 常见缓存淘汰算法
- FIFO:先进先出,在这种淘汰算法中,先进入缓存的会先被淘汰,会导致命中率很低。
- LRU:最近最少使用算法,每次访问数据都会将其放在我们的队尾,如果需要淘汰数据,就只需要淘汰队首即可。
- LFU:最近最少频率使用,利用额外的空间记录每个数据的使用频率,然后选出频率最低进行淘汰。这样就避免了 LRU 不能处理时间段的问题。
1.2 LRU和LFU缺点:
-
LRU 实现简单,在一般情况下能够表现出很好的命中率,是一个“性价比”很高的算法,平时也很常用。虽然 LRU 对突发性的稀疏流量(sparse bursts)表现很好,但同时也会产生缓存污染,举例来说,如果偶然性的要对全量数据进行遍历,那么“历史访问记录”就会被刷走,造成污染。
-
如果数据的分布在一段时间内是固定的话,那么 LFU 可以达到最高的命中率。但是 LFU 有两个缺点,第一,它需要给每个记录项维护频率信息,每次访问都需要更新,这是个巨大的开销;第二,对突发性的稀疏流量无力,因为前期经常访问的记录已经占用了缓存,偶然的流量不太可能会被保留下来,而且过去的一些大量被访问的记录在将来也不一定会使。
1.3 W-TinyLFU 算法:
TinyLFU 算法:
-
解决第一个问题是采用了 Count–Min Sketch 算法。
-
为了解决 LFU 不便于处理随时间变化的热度变化问题,TinyLFU 采用了基于 “滑动时间窗” 的热度衰减算法,简单理解就是每隔一段时间,便会把计数器的数值减半,以此解决 “旧热点” 数据难以清除的问题。
W-TinyLFU算法:
W-TinyLFU(Windows-TinyLFU):W-TinyLFU 又是 TinyLFU 的改进版本。TinyLFU 在实现减少计数器维护频率的同时,也带来了无法很好地应对稀疏突发访问的问题,所谓稀疏突发访问是指有一些绝对频率较小,但突发访问频率很高的数据,此时 TinyLFU 就很难让这类元素通过 Sketch 的过滤,因为它们无法在运行期间积累到足够高的频率。应对短时间的突发访问是 LRU 的强项,W-TinyLFU 就结合了 LRU 和 LFU 两者的优点,从整体上看是它是 LFU 策略,从局部实现上看又是 LRU 策略。具体做法是将新记录暂时放入一个名为 Window Cache 的前端 LRU 缓存里面,让这些对象可以在 Window Cache 中累积热度,如果能通过 TinyLFU 的过滤器,再进入名为 Main Cache 的主缓存中存储,主缓存根据数据的访问频繁程度分为不同的段(LFU 策略,实际上 W-TinyLFU 只分了两段),但单独某一段局部来看又是基于 LRU 策略去实现的(称为 Segmented LRU)。每当前一段缓存满了之后,会将低价值数据淘汰到后一段中去存储,直至最后一段也满了之后,该数据就彻底清理出缓存。
1.3.1 常用配置参数
expireAfterWrite:写入间隔多久淘汰;
expireAfterAccess:最后访问后间隔多久淘汰;
refreshAfterWrite:写入后间隔多久刷新,当加载不到新数据采用旧数据时便可设置此参数。
maximumSize:缓存 key 的最大个数;
softValues:value设置为软引用,在内存溢出前可以直接淘汰;
executor:选择自定义的线程池,默认的线程池实现是 ForkJoinPool.commonPool();
recordStats:缓存的统计数据,比如命中率等;
removalListener:缓存淘汰监听器;
1.3.2 同步加载数据
实战代码:
public class AdsPreCheckConfigListCache {
private static Logger LOGGER = LoggerFactory.getLogger(AdsPreCheckConfigListCache.class);
private LoadingCache<Integer, String> cache = null;
/**
* @description 初始化caffine
* @author idslilang
* @updateTime 2021/6/2 14:48
* @Return
*/
public void init() {
this.cache = Caffeine.newBuilder().initialCapacity(3000).maximumSize(10000)
.refreshAfterWrite(1,TimeUnit.SECONDS)
.expireAfterWrite(1, TimeUnit.SECONDS)
.executor(ThreadPoolUtils.getThreadPoolExecutor())
.recordStats()
.build(initLoader());
}
public LoadingCache<Integer, String> getCache(){
return cache;
}
private CacheLoader<Integer, String> initLoader() {
return new CacheLoader<Integer, String>() {
@Override
public @Nullable String load(@NonNull Integer integer) throws Exception {
System.out.println("i come load---->" + integer);
return String.valueOf("load---->"+integer);
}
@Override
public @Nullable String reload(@NonNull Integer key, @NonNull String oldValue) throws Exception {
System.out.println("i come reload---->" + oldValue);
return String.valueOf("reload---->"+key);
}
};
}
public Object get(Integer bizId){
return cache.get(bizId);
}
public static void main(String[] args) throws InterruptedException, TimeoutException, ExecutionException {
AdsPreCheckConfigListCache cache = new AdsPreCheckConfigListCache();
cache.init();
while (true){
cache.get(1);
TimeUnit.SECONDS.sleep(1);
}
}
}
输出结果:
i come load---->1
i come load---->1
i come load---->1
i come load---->1
i come load---->1
i come load---->1
当cache如下时:
this.cache = Caffeine.newBuilder().initialCapacity(3000).maximumSize(10000)
.refreshAfterWrite(1,TimeUnit.SECONDS)
.expireAfterWrite(3, TimeUnit.SECONDS)
.executor(ThreadPoolUtils.getThreadPoolExecutor())
.recordStats()
.build(initLoader());
输出结果:
load---->1
load---->1
reload---->1
reload---->1
reload---->1
reload---->1
reload---->1
reload---->1
reload---->1
监听过期数据
this.cache = Caffeine.newBuilder().initialCapacity(3000).maximumSize(10000)
.refreshAfterWrite(1,TimeUnit.SECONDS)
.expireAfterWrite(3, TimeUnit.SECONDS)
.executor(ThreadPoolUtils.getThreadPoolExecutor())
.removalListener(new RemovalListener<Object, Object>() {
@Override
public void onRemoval(@Nullable Object key, @Nullable Object value, @NonNull RemovalCause removalCause) {
System.out.println(key);
System.out.println(value);
}
})
.recordStats()
.build(initLoader());
主动请求的时候才会监听到,不请求的时候无法监听到。
当要cache自动清除数据,预先加载时候可以如下配置:
但是这种存在一种风险,当大量key同一时间失效的时候,会造成瞬间大量线程访问数据库,可以考虑重新申明一个队列,监听队列处理。
public void init() {
this.cache = Caffeine.newBuilder().initialCapacity(3000).maximumSize(10000)
.expireAfterWrite(1, TimeUnit.SECONDS)
.executor(ThreadPoolUtils.getThreadPoolExecutor())
.removalListener(new RemovalListener<Integer, String>() {
@Override
public void onRemoval(@Nullable Integer key, @Nullable String value, @NonNull RemovalCause removalCause) {
System.out.println("expire la ");
get(key);
}
})
.scheduler(Scheduler.forScheduledExecutorService( Executors.newSingleThreadScheduledExecutor()))
.buildAsync(initLoader());
}
1.3.3 异步加载数据
public class AdsPreCheckConfigListCache {
private static Logger LOGGER = LoggerFactory.getLogger(AdsPreCheckConfigListCache.class);
private AsyncLoadingCache<Integer, String> cache = null;
/**
* @description 初始化caffine
* @author idslilang
* @updateTime 2021/6/2 14:48
* @Return
*/
public void init() {
this.cache = Caffeine.newBuilder().initialCapacity(3000).maximumSize(10000)
.expireAfterWrite(1, TimeUnit.SECONDS)
.executor(ThreadPoolUtils.getThreadPoolExecutor())
.removalListener(new RemovalListener<Integer, String>() {
@Override
public void onRemoval(@Nullable Integer key, @Nullable String value, @NonNull RemovalCause removalCause) {
System.out.println("expire la ");
}
})
.buildAsync(initLoader());
}
public AsyncLoadingCache<Integer, String> getCache(){
return cache;
}
private AsyncCacheLoader<Integer, String> initLoader() {
return new AsyncCacheLoader<Integer, String>() {
@Override
public @NonNull CompletableFuture<String> asyncLoad(@NonNull Integer key, @NonNull Executor executor) {
System.out.println("i come load ");
return CompletableFuture.supplyAsync(()->{
return String.valueOf("load---->"+key);
},executor);
}
@Override
public @NonNull CompletableFuture<String> asyncReload(@NonNull Integer key, @NonNull String oldValue, @NonNull Executor executor) {
System.out.println("i come reload ");
return CompletableFuture.supplyAsync(()->{
return String.valueOf("reload---->"+key);
},executor);
}
};
}
public Object get(Integer bizId){
try {
return cache.get(bizId).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) throws InterruptedException, TimeoutException, ExecutionException {
AdsPreCheckConfigListCache cache = new AdsPreCheckConfigListCache();
cache.init();
while (true){
System.out.println(cache.get(1));
TimeUnit.SECONDS.sleep(6);
}
}
}
异步加载数据时候,可以对future设置超时时间,实现更加灵活的控制。
二:异步编程CompleteFuture实战
2.1 Future获取任务结果
使用Future
获得异步执行结果时,要么调用阻塞方法get()
,要么轮询看isDone()
是否为true
,这两种方法主线程也会被迫等待。
从Java 8开始引入了CompletableFuture
,它针对Future
做了改进,可以传入回调对象,当异步任务完成或者发生异常时,自动调用回调对象的回调方法。
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> stringFuture = executor.submit(new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(2000);
return "future thread";
}
});
Thread.sleep(1000);
System.out.println("main thread");
System.out.println(stringFuture.get());
}
2.2 CompletableFuture 异步执行任务
2.2.1 异步任务接口
//接受Runnable,无返回值,使用ForkJoinPool.commonPool()线程池public static CompletableFuture<Void> runAsync(Runnable runnable)//接受Runnable,无返回值,使用指定的executor线程池 public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor) //接受Supplier,返回U,使用ForkJoinPool.commonPool()线程池 这个线程池默认线程数是 CPU 的核数。public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) //接受Supplier,返回U,使用指定的executor线程池 public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
DEMO:
public CompletableFuture<String> getCompletableFutureData(){
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(()->{
return "return world";
}, executor);
return completableFuture;
}
public void runAsync(){
CompletableFuture.runAsync(()->{
//do something async
}, executor);;
}
2.2.2 设置任务结果
public boolean complete(T value);
public boolean completeExceptionally(Throwable ex);
CompletableFuture.completedFuture();
设置结果DEMO1:
public void runAsync() throws ExecutionException, InterruptedException {
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(()->{
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "我正在返回异步结果";
},executor);
completableFuture.complete("单独设置返回结果");
System.out.println(completableFuture.get());
TimeUnit.SECONDS.sleep(6);
System.out.println(completableFuture.get());
}
输出结果:
单独设置返回结果
单独设置返回结果
设置结果DEMO2:
public void runAsync() throws ExecutionException, InterruptedException { CompletableFuture<String> completableFuture =CompletableFuture.completedFuture("我完成了任务"); completableFuture.complete("单独设置返回结果"); System.out.println(completableFuture.get()); TimeUnit.SECONDS.sleep(6); System.out.println(completableFuture.get());}
输出结果:
我完成了任务我完成了任务
需要注意点:
一旦 complete 设置成功,CompletableFuture 返回结果就不会被更改,即使后续 CompletableFuture 任务执行结束。同样,申明一个完成任务的future(CompletableFuture.completedFuture("我完成了任务")),后续再对其操作也不起作用。
异常任务设置DEMO3:
public void runAsync() throws ExecutionException, InterruptedException { CompletableFuture<String> completableFuture =CompletableFuture.supplyAsync(()->{ return "我正在运行任务"; },executor); completableFuture.completeExceptionally(new RuntimeException("我发生了异常")); System.out.println(completableFuture.get());}
输出结果中将不会得到任务结果,将会返回异常信息,项目中可以根据任务结果设置自定义异常信息,便于统一处理任务结果或者做任务监控。
2.2.3 串行关系
//有返回值CompletableFuture#thenApply//无返回值CompletableFuture#thenAccept//异步执行CompletableFuture#thenApplyAsyncCompletableFuture#thenAcceptAsync(Consumer<? super T> action);
代码DEMO:
CompletableFuture completableFuture = CompletableFuture.supplyAsync(()->{
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
return " supplyAsync start --->";
},executor).thenApply((res)->{
//收到上层传递结果,继续传递结果
return res+"thenApply continue ---> ";
}).thenAccept(res->{
// 收到上层传递结果,不继续传递结果,返回null
System.out.println(res+"thenAccept done ");
}).thenAccept(res->{
//收到结果null
System.out.println(res+"thenAccept done ");
});
当使用同步执行的时候,需要等到所有串行结果执行完毕future才能获取到值。调用thenApply方法执行第二个任务时,则第二个任务和第一个任务是共用同一个线程池。调用thenApplyAsync执行第二个任务时,则第一个任务使用的是你自己传入的线程池,如果没有传入线程池,第二个任务使用的是ForkJoin线程池,当获取completableFuture任务结果时,也需要等待所有串行任务执行完毕才行。
注意点:
当我们完成了一个异步任务,还需要操作一些与异步任务相关的其他操作,如刷缓存,写日志等。则可以采用如下方式实现
public CompletableFuture runAsync() throws ExecutionException, InterruptedException {
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
return " supplyAsync start --->";
}, executor);
//链路已经断开,后续不影响completableFuture 返回值,业务方获取到的completableFuture信息为“supplyAsync start --->”
completableFuture.thenAcceptAsync((res) -> {
//执行任务
}, executor);
return completableFuture;
}
2.2.4 并行执行关系
由于异步执行同上类似,不再进行展示
//等待两个对象执行完毕,获取返回结果CompletableFuture#thenCombine//等待两个对象执行完毕,不获取返回结果CompletableFuture#runAfterBoth//所有future对象执行完毕,不获取返回结果CompletableFuture#allOf
代码DEMO:
public void runAsync() { CompletableFuture<Integer> moneyFutrue = CompletableFuture.supplyAsync(() -> { System.out.println("查询钱包余额"); return 1000; }, executor); CompletableFuture<Integer> foodCostFuture = CompletableFuture.supplyAsync(() -> { System.out.println("查询食物价格"); return 100; }, executor); CompletableFuture<Integer> resData = moneyFutrue.thenCombine(foodCostFuture, (money, foodCost) -> { System.out.println("剩余额度:"); return money - foodCost; }); CompletableFuture<Integer> resData = moneyFutrue.thenCombine(foodCostFuture, (money, foodCost) -> { System.out.println("剩余额度:"); System.out.println(money - foodCost); });}
代码DEMO2: allof 执行 获取所有任务结果,对于实际的项目中,可以定义需要的对象去接收传递参数。
public CompletableFutur<List<Integer>> runAsync() { CompletableFuture<Integer> moneyFutrue = CompletableFuture.supplyAsync(() -> { System.out.println("去王庄收的食物数量:"); return 1000; }, executor); CompletableFuture<Integer> foodCostFuture = CompletableFuture.supplyAsync(() -> { System.out.println("去李庄收的食物数量:"); return 100; }, executor); List<CompletableFuture<Integer>> futures = new ArrayList<>(); futures.add(moneyFutrue); futures.add(foodCostFuture); CompletableFuture<Void> completableFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); List<Integer> results = new ArrayList<>(); CompletableFuture<List<Integer>> resFutur= completableFuture.thenApply((res) -> { for (CompletableFuture<Integer> cmplfuture:futures){ //如果取不到,设置一个默认值 results.add(cmplfuture.getNow(0)); } return results; }); return resFutur; }
此时可以用resFutur中的get或者join方法去获取异步任务执行结果。
2.2.5 OR执行关系
//等待任何一个对象执行完毕,获取返回结果CompletableFuture#acceptEither//等待任何对象执行完毕,不获取返回结果CompletableFuture#runAfterEither//所有future对象执行完毕,不获取返回结果CompletableFuture#anyOf
代码DEMO:
public void runAsync() { CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> { sleep(5, TimeUnit.SECONDS); return "坐公交车"; });// 1 CompletableFuture<String> cf2 = cf.supplyAsync(() -> { sleep(3, TimeUnit.SECONDS); return "坐地铁"; }); CompletableFuture<String> cf3 = cf2.applyToEither(cf, s -> s); System.out.println(cf2.join());}
输出结果:
坐地铁
代码DEMO2:
public void runAsync() throws ExecutionException, InterruptedException {
CompletableFuture<String> cf
= CompletableFuture.supplyAsync(() -> {
sleep(5, TimeUnit.SECONDS);
return "坐公交车";
});// 1
CompletableFuture<String> cf2 = cf.supplyAsync(() -> {
sleep(3, TimeUnit.SECONDS);
return "坐地铁";
});
ArrayList<CompletableFuture<String>> futures = new ArrayList<CompletableFuture<String>>();
futures.add(cf);
futures.add(cf2);
CompletableFuture<Object> res = CompletableFuture.anyOf(cf,cf2);
System.out.println(res.get());
}
数据结果:
坐地铁
2.2.6 异常处理
//whenComplete 与 handle 方法就类似于 try..catch..finanlly 中 finally 代码块。无论是否发生异常,都将会执行的。这两个方法区别在于 handle 支持返回结果。
CompletableFuture#handle
CompletableFuture#whenComplete
//使用方式类似于 try..catch 中 catch 代码块中异常处理。
CompletableFuture#exceptionally
代码DEMO:
public void runAsync() throws ExecutionException, InterruptedException {
CompletableFuture<String> cf
= CompletableFuture.supplyAsync(() -> {
int a = 1 / 0;
sleep(5, TimeUnit.SECONDS);
return "坐公交车";
});
cf.exceptionally(ex->{
return null;
}).thenAccept(res->{
System.out.println(res);
});
}
数据结果:
null
代码DEMO2:
public void runAsync() throws ExecutionException, InterruptedException {
CompletableFuture<String> cf
= CompletableFuture.supplyAsync(() -> {
int a = 1 / 0;
sleep(5, TimeUnit.SECONDS);
return "坐公交车";
});
CompletableFuture<String> cf2 = cf.supplyAsync(() -> {
sleep(3, TimeUnit.SECONDS);
return "坐地铁";
});
List<CompletableFuture<String>> futures = new ArrayList<>();
futures.add(cf);
futures.add(cf);
//如果不捕获异常,是无法执行到thenApply去取结果的
CompletableFuture<List<String>> allRes= CompletableFuture.allOf(cf, cf2).exceptionally((ex) -> {
return null;
}).thenApply(res -> {
List<String> result = new ArrayList<>();
for (CompletableFuture<String> future : futures) {
result.add(future.getNow(""));
}
return result;
});
}
代码DEMO3:
public void runAsync() throws ExecutionException, InterruptedException {
CompletableFuture<String> cf
= CompletableFuture.supplyAsync(() -> {
int a = 1 / 0;
sleep(5, TimeUnit.SECONDS);
return "坐公交车";
});
CompletableFuture<String> cf2 = cf.supplyAsync(() -> {
sleep(3, TimeUnit.SECONDS);
return "坐地铁";
});
List<CompletableFuture<String>> futures = new ArrayList<>();
futures.add(cf);
futures.add(cf);
CompletableFuture<List<String>> allRes= CompletableFuture.allOf(cf, cf2).whenComplete((res,ex)->{
System.out.println(res);
}).thenApply(res -> {
List<String> result = new ArrayList<>();
for (CompletableFuture<String> future : futures) {
result.add(future.getNow(""));
}
return result;
});
//先异常捕获,再进行任务处理,
CompletableFuture<List<String>> allRes= CompletableFuture.allOf(cf, cf2).exceptionally(ex->{
return null;
}).thenApply(res -> {
List<String> result = new ArrayList<>();
for (CompletableFuture<String> future : futures) {
result.add(future.getNow(""));
}
return result;
}).whenComplete((res,ex)->{
System.out.println("fasdfdsf");
});
}
如上代码中:当任务中有错误的时候,thenApply是无法执行的,除非进行异常捕获 ,如果任务中没有错误,thenApply可以继续执行,实际项目中不推荐使用,正常业务逻辑处理中,可以先对批量任务进行异常捕获,然后再对结果进行处理。
2.2.7 超时时间控制
CompletableFuture 超时时间控制可以采用两种方式进行控制:
- 对CompletableFuture设置超时时间
- 业务方通过CompletableFuture获取结果时候设置超时时间
DEMO代码1 如下:
public void runAsync() throws ExecutionException, InterruptedException, TimeoutException { CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> { sleep(5, TimeUnit.SECONDS); return "我超时了"; }).orTimeout(1,TimeUnit.SECONDS); sleep(2,TimeUnit.SECONDS); System.out.println(cf.isDone()); sleep(6,TimeUnit.SECONDS); System.out.println(cf.get()); }
输出结果:
trueException in thread "main" java.util.concurrent.ExecutionException: java.util.concurrent.TimeoutException at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:395) at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1999) at com.idsidslilang.go.future.FutureService.runAsync(FutureService.java:25) at com.idsidslilang.go.future.FutureService.main(FutureService.java:33)Caused by: java.util.concurrent.TimeoutException at java.base/java.util.concurrent.CompletableFuture$Timeout.run(CompletableFuture.java:2792) at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java) at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:834)
可以看出,设置了超时时间以后,在运行超过了两秒时,future任务就已经终止。
第二种方式:
public void runAsync() {
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
sleep(5, TimeUnit.SECONDS);
return "我超时了";
});
try {
sleep(2,TimeUnit.SECONDS);
System.out.println(cf.isDone());
System.out.println(cf.get(2,TimeUnit.SECONDS));
}catch (TimeoutException ex){
ex.printStackTrace();
}
}
输出结果:
false
java.util.concurrent.TimeoutException
at java.base/java.util.concurrent.CompletableFuture.timedGet(CompletableFuture.java:1886)
at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2021)
at com.idsidslilang.go.future.FutureService.runAsync(FutureService.java:23)
at com.idsidslilang.go.future.FutureService.main(FutureService.java:37)
2.2.8 超时时间生效判断:
CompletableFuture从设置超时时间处开始进行计时,定义future时就已经在进行异步计算。
代码DEMO:
public void runAsync() throws ExecutionException, InterruptedException, TimeoutException {
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
sleep(6, TimeUnit.SECONDS);
return "我超时了";
}).orTimeout(1,TimeUnit.SECONDS);
System.out.println(cf.isDone());
System.out.println(cf.get());;
}
输出结果:
false
Exception in thread "main" java.util.concurrent.ExecutionException: java.util.concurrent.TimeoutException
at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:395)
at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1999)
at com.idsidslilang.go.future.FutureService.runAsync(FutureService.java:20)
at com.idsidslilang.go.future.FutureService.main(FutureService.java:27)
Caused by: java.util.concurrent.TimeoutException
at java.base/java.util.concurrent.CompletableFuture$Timeout.run(CompletableFuture.java:2792)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
代码DEMO2:
public void runAsync() throws ExecutionException, InterruptedException, TimeoutException {
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
sleep(4, TimeUnit.SECONDS);
return "我超时了";
});
System.out.println(cf.isDone());
sleep(5,TimeUnit.SECONDS);
cf.orTimeout(1,TimeUnit.SECONDS);
System.out.println(cf.get());;
}
输出结果:
false
我超时了
代码DEMO3:
public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
sleep(4, TimeUnit.SECONDS);
return "我超时了";
});
sleep(2,TimeUnit.SECONDS);
System.out.println(cf.get(1,TimeUnit.SECONDS));
}
输出结果:
Exception in thread "main" java.util.concurrent.TimeoutException
at java.base/java.util.concurrent.CompletableFuture.timedGet(CompletableFuture.java:1886)
at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2021)
at com.idsidslilang.go.future.FutureService.main(FutureService.java:33)
代码DEMO4:
public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
sleep(4, TimeUnit.SECONDS);
return "我超时了";
});
sleep(4,TimeUnit.SECONDS);
System.out.println(cf.get(1,TimeUnit.SECONDS));
}
输出结果:
我超时了