Merge branch 'master' of https://gitea.rikako.cc/rikako/rikako-note
This commit is contained in:
114
java se/CompletableFuture.md
Normal file
114
java se/CompletableFuture.md
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
# CompletableFuture
|
||||||
|
对于Future对象,需要调用其get方法来获取值,get方法会阻塞当前线程直到该值可获取。
|
||||||
|
而CompletableFuture实现了Future接口,并且其提供了其他机制来获取result。通过CompletableFuture可以注册一个callback,该回调会在result可获取时调用。
|
||||||
|
```java
|
||||||
|
CompletableFuture<String> f = . . .;
|
||||||
|
f.thenAccept(s -> Process the result string s);
|
||||||
|
```
|
||||||
|
**通过这种方法,就无需等待result处于可获取状态之后再对其进行处理。**
|
||||||
|
通常情况下,很少有方法返回类型为CompletableFuture,此时,需要自己指定返回类型。CompletableFuture使用方法如下:
|
||||||
|
```java
|
||||||
|
public CompletableFuture<String> readPage(URL url)
|
||||||
|
{
|
||||||
|
return CompletableFuture.supplyAsync(() ->
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return new String(url.openStream().readAllBytes(), "UTF-8");
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
throw new UncheckedIOException(e);
|
||||||
|
}
|
||||||
|
}, executor);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
> Compatable.supplyAsync方法接受一个Supplier而不是一个Callable,虽然它们都没有参数且返回一个T,但是Callable允许抛出Exception,但Supplier不许抛出Checked Exception。
|
||||||
|
> 并且,**再没有显式为supplyAsync方法指定Executor参数时,其会默认采用ForkJoinPool.commonPool()**
|
||||||
|
|
||||||
|
Complatable可以以两种方式执行结束:(1)是否有返回值(2)是否有未捕获异常。要处理以上两种情况,需要使用whenComplete方法。提供给whenComplete函数的方法将会和执行result(如果没有返回值则为null)与抛出异常exception(如果没有则为null)一起被调用。
|
||||||
|
```java
|
||||||
|
f.whenComplete((s, t) -> {
|
||||||
|
if (t == null)
|
||||||
|
{
|
||||||
|
Process the result s;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Process the Throwable t;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
CompletableFuture可以手动设置completable value。虽然CompletableFuture对象的完成状态在supplyAsync方法的task执行结束之后会被隐式设置为已完成,但是通过手动设置完成状态可以提供更大的灵活性,例如可以同时以两种方式进行计算,任一方式先计算结束则将CompletableFuture对象的完成状态设置为已完成:
|
||||||
|
```java
|
||||||
|
var f = new CompletableFuture<Integer>();
|
||||||
|
executor.execute(() ->
|
||||||
|
{
|
||||||
|
int n = workHard(arg);
|
||||||
|
f.complete(n);
|
||||||
|
});
|
||||||
|
executor.execute(() ->
|
||||||
|
{
|
||||||
|
int n = workSmart(arg);
|
||||||
|
f.complete(n);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
如果想要以抛出异常的方式将CompletableFuture对象的完成状态设置为已完成,可以调用completeExcetpionally方法:
|
||||||
|
```java
|
||||||
|
Throwable t = . . .;
|
||||||
|
f.completeExceptionally(t);
|
||||||
|
```
|
||||||
|
> 在不同的线程中调用同一个对象的complete或completeExceptionally方法是线程安全的,如果该completableFuture对象的完成状态为已完成,那么再次调用complete或completeExceptionally方法无效。
|
||||||
|
|
||||||
|
> ## Caution
|
||||||
|
> 并不像Future对象,CompletableFuture对象在调用其cancel方法时,并不会对其task执行的线程进行中断操作,而是**仅仅将completableFuture对象的完成状态设置为抛出CancellationException的已完成状态。**
|
||||||
|
> 因为对于一个CompletableFuture对象,可能并没有一个唯一的线程对应其task的执行(future对象对应task可能未在任何线程中执行,也可能在多个线程中执行)
|
||||||
|
|
||||||
|
## CompletableFuture组合
|
||||||
|
异步方法的非阻塞调用是通过callback来实现的,调用者注册一个action,该action在task被完成时调用。如果注册的action仍然是异步的,那么该action的下一个action位于另一个完全不同的callback中。
|
||||||
|
```java
|
||||||
|
f1.whenComplete((s,t)->{
|
||||||
|
CompletableFuture<> f2 = ...
|
||||||
|
f2.whencomplete((s,t)->{
|
||||||
|
//...
|
||||||
|
})
|
||||||
|
})
|
||||||
|
```
|
||||||
|
这样可能会造成callback hell的情况,并且异常处理也特别不方便,由此CompletableFuture提供了一种机制来组合多个CompletableFuture:
|
||||||
|
```java
|
||||||
|
CompletableFuture<String> contents = readPage(url);
|
||||||
|
CompletableFuture<List<URL>> imageURLs =
|
||||||
|
contents.thenApply(this::getLinks);
|
||||||
|
```
|
||||||
|
在completableFuture对象上调用thenApply方法,thenApply方法也不会阻塞,其会返回另一个completableFuture对象,并且,当第一个Future对象contents返回之后,返回结果会填充到getLinks方法的参数中。
|
||||||
|
### CompletableFuture常用方法
|
||||||
|
CompletableFuture组合可以有如下常用方法:
|
||||||
|
- thenApply(T -> U):对CompletableFuture对象的返回结果执行操作,并且产生一个返回值
|
||||||
|
- thenAccept(T -> void):类似thenApply,操作上一个future的返回值,但是返回类型为void
|
||||||
|
- handle(T,Throwable)->U:处理上一个future返回的result并且产生一个返回值
|
||||||
|
- thenCompose(T->CompletableFuture\<U\>):将上一个Future返回值作为参数传递,并且返回CompletableFuture\<U\>
|
||||||
|
- whenComplete(T,Throwable)->void:类似于handle,但是不产生返回值
|
||||||
|
- exceptionally(Throwable->T):处理异常并返回一个结果
|
||||||
|
- completeOnTimeout(T,long,TimeUnit):当超时时,将传入的参数T作为返回结果
|
||||||
|
- orTimeOut(long,TimeUnit):当超时时,产生一个TimeoutExcetpion作为结果
|
||||||
|
- thenRun(Runnable):执行该Runnable并且返回一个CompletableFuture<void>
|
||||||
|
如上的每一个方法都有另一个Async版本,如thenApplyAsync:
|
||||||
|
```java
|
||||||
|
CompletableFuture<U> future.thenApply(f);
|
||||||
|
CompletableFuture<U> future.thenApplyAsync(f);
|
||||||
|
```
|
||||||
|
thenApply中,会对future的返回结果执行f操作;而在thenApplyAsync中,对f操作的执行会在另一个线程中。
|
||||||
|
thenCompose通常用来连接两个返回类型都为CompletableFuture的方法。
|
||||||
|
|
||||||
|
### CompletableFuture Combine
|
||||||
|
- thenCombine(CompletableFuture\<U\>,(T,U)->V):执行两个future,并且通过f对两个future的返回值进行combine
|
||||||
|
- thenAcceptBoth(CompletableFuture\<U\>,(T,U)->Void):执行两个future,并通过f处理两个future的返回值,但是返回类型为void
|
||||||
|
- runAfterBoth(CompletableFuture\<?\>,Runnable):当两个future都执行完之后,执行Runnable
|
||||||
|
- applyToEither(CompletableFuture\<T\>,(T)-> U):当任一future执行完成,通过该result产生返回值
|
||||||
|
- acceptEither(CompletableFuture\<T\>,T->Void):类似applyToEither,但是返回值为void
|
||||||
|
- runAfterEither(CompletableFuture\<?\>,Runnable):在任一future执行完成之后,执行Runnable
|
||||||
|
- static allOf(CompletableFuture\<?\>...):在参数中所有future执行完成之后,返回的future处于完成状态
|
||||||
|
- static anyOf(CompletableFuture\<?\>...):在参数中任一future执行完成之后,返回的future处于完成状态
|
||||||
|
|
||||||
|
### completedFuture
|
||||||
|
CompletableFuture.completedFuture会返回一个已经执行完成的CompletableFuture对象,并且该future对象返回值为T
|
||||||
12
spring/Spring core/@Validated, @Valid.md
Normal file
12
spring/Spring core/@Validated, @Valid.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# @Validated & @Valid
|
||||||
|
## @Validated
|
||||||
|
@Validated可以用于方法级别,方法参数级别以及类级别
|
||||||
|
- 类级别:当@Validated注解用于类级别时,该类中所有的约束(例如@Max,@Size)都会被校验
|
||||||
|
- 参数级别:类似于@Valid
|
||||||
|
- 方法级别:将@Validated注解用于方法级别,会override group信息,但是不会插入切面
|
||||||
|
|
||||||
|
可以将@Validated作用于spring mvc handler的参数,也可以将其作为方法级别的验证。方法级别的验证允许覆盖validation group,但是不会作为切面。
|
||||||
|
> @Validated实现原理基于spring aop,故而只有标注了@Validated注解的bean对象才会被代理并拦截
|
||||||
|
|
||||||
|
## @Valid
|
||||||
|
相对于@Validated注解,@Valid注解允许应用于返回类型和field上,故而通过@Valid注解可以用于嵌套类的校验
|
||||||
@@ -1,3 +1,22 @@
|
|||||||
|
- [Spring Boot Async](#spring-boot-async)
|
||||||
|
- [Spring Executor和Scheduler的自动配置](#spring-executor和scheduler的自动配置)
|
||||||
|
- [Task Execution and Scheduling](#task-execution-and-scheduling)
|
||||||
|
- [Task Execution Abstraction](#task-execution-abstraction)
|
||||||
|
- [TaskExecutor接口的实现种类](#taskexecutor接口的实现种类)
|
||||||
|
- [TaskExecutor的使用](#taskexecutor的使用)
|
||||||
|
- [Spring TaskScheduler Abstraction](#spring-taskscheduler-abstraction)
|
||||||
|
- [Trigger接口](#trigger接口)
|
||||||
|
- [Trigger实现类](#trigger实现类)
|
||||||
|
- [TaskScheduler实现类](#taskscheduler实现类)
|
||||||
|
- [对任务调度和异步执行的注解支持](#对任务调度和异步执行的注解支持)
|
||||||
|
- [启用Scheduling注解](#启用scheduling注解)
|
||||||
|
- [@Scheduled注解](#scheduled注解)
|
||||||
|
- [@Async注解](#async注解)
|
||||||
|
- [@Async方法的异常处理](#async方法的异常处理)
|
||||||
|
- [Cron表达式](#cron表达式)
|
||||||
|
- [Macros(宏)](#macros宏)
|
||||||
|
|
||||||
|
|
||||||
# Spring Boot Async
|
# Spring Boot Async
|
||||||
## Spring Executor和Scheduler的自动配置
|
## Spring Executor和Scheduler的自动配置
|
||||||
当当前上下文中没有Executor类型的bean对象时,spring boot会自动配置一个ThreadPoolTaskExecutor类型的bean对象,并且将该bean对象和异步task执行(@EnableAsync)和spring mvc异步请求处理关联在一起。
|
当当前上下文中没有Executor类型的bean对象时,spring boot会自动配置一个ThreadPoolTaskExecutor类型的bean对象,并且将该bean对象和异步task执行(@EnableAsync)和spring mvc异步请求处理关联在一起。
|
||||||
@@ -180,3 +199,40 @@ public class SampleBeanInitializer {
|
|||||||
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
### @Async方法的异常处理
|
||||||
|
当@Async方法的返回类型是Future类型时,处理async方法执行时抛出的异常非常简单,当在Future对象上调用get方法时异常会被抛出。**但当@Async方法的返回类型是void时,执行时抛出的异常既无法被捕获也无法被传输。可以指定一个AsyncUncaughtExceptionHandler来处理此类异常。**
|
||||||
|
```java
|
||||||
|
public class MyAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
|
||||||
|
// handle exception
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
### Cron表达式
|
||||||
|
在Spring中,cron表达式格式如下:
|
||||||
|
\* \* \* \* \* \*
|
||||||
|
其代表为(s,min,hour,day of month/\*(1~31)\*/,month/\*(1~12)\*/,day of week/\*(0~7,0 or 7 is sun)\*/)
|
||||||
|
> 规则如下:
|
||||||
|
> - 所有字段都可以用(*)来匹配所有值
|
||||||
|
> - 逗号(,)可以用来分隔同一字段中多个值
|
||||||
|
> - 分号(-)可以用来指定范围,指定的范围左右都包含,eg,1-5代表[1,5]
|
||||||
|
> - 在范围(或是*)后跟随下划线(/)代表间隔,如在分钟字段指定*/20,代表该小时内每过20min
|
||||||
|
> - 对于月份或者day of week,可以使用英文名的前三个字母来代替,大小写不敏感
|
||||||
|
> - 在day of month或day of week字段中可以包含L字母
|
||||||
|
> - 在day of month字段,L代表该月的最后一天,在该字段还可以为L指定一个负的偏移量,如L-n代表该月的倒数第n+1天
|
||||||
|
> - 在day of week字段,L代表该周的最后一天,L前还可以前缀月份的数字或是月份的前三个字母(dL或DDDL,如7L或sunL,代表该月份的最后一个星期日),代该月份的最后一个day of week
|
||||||
|
> - day of month字段可以指定为nW,代表离day of month为n最近的一个工作日,如果n为周六,则该该字段代表的值为周五的day of month,如果n为周六,则该字段代表下周一的day of month(如果n为1其位于周六,其也代表下周一的day of month,1W代表该月的第一个工作日)
|
||||||
|
> - 如果day of month的值为LW,则代表该月的最后一个工作日
|
||||||
|
> - day of week字段还能指定为d#n或DDD#n的形式,代表该月的的第几个d in week(例如SUN#2,代表当前月的第二个星期日)
|
||||||
|
|
||||||
|
#### Macros(宏)
|
||||||
|
Cron表达式可读性不太好,可以使用如下预定义的宏:
|
||||||
|
| Macro | meaning |
|
||||||
|
|:-:|:-:|
|
||||||
|
| @yearly (or @annually) | once a year (0 0 0 1 1 *) |
|
||||||
|
| @monthly | once a month (0 0 0 1 * *) |
|
||||||
|
| @weekly | once a week (0 0 0 * * 0) |
|
||||||
|
| @daily (or @midnight) | once a day (0 0 0 * * *), or |
|
||||||
|
| @hourly | once an hour, (0 0 * * * *) |
|
||||||
|
|||||||
Reference in New Issue
Block a user