java8
********************************************************************************
java8编程知识,流式特性可参考http://www.php.cn/java-article-353260.html
********************************************************************************
java8中Map新增了一个computeIfAbsent()方法,判断是否存在key,若存在则返回value,否则则执行函数
// Map.computeIfAbsent(key,Function<T,R>)
public static Long getLong(Integer integer) {
Map<Integer, Long> map = Maps.newHashMap();
long f = map.computeIfAbsent(integer, p -> {
Integer result = p * 2;
return result.longValue();
});
return f;
}
多线程:CompletableFuture,使用多线程时需要格外注意细节,否则容易造成系统业务混乱!使用并行流时并行数与系统的内核数量一致,线程数默认也与内核数一致,而线程数可以通过设置线程池来确定,不过线程池的数量要适合否则容易容易导致效率更低。
——不使用工厂方法创建CompletableFuture
public CompletableFuture<String> completableFuture() {
CompletableFuture<String> future = new CompletableFuture<>();
new Thread(() -> {
System.out.println("请开始你的表演...");
try {
Thread.sleep(1000L);
// 接受返回值
future.complete("hello World");
} catch (InterruptedException e) {
e.printStackTrace();
// 捕捉线程中抛出的异常,会抛到调用者
future.completeExceptionally(e);
}
})
// 必须启动线程,否则future无法储存返回值
.start();
return future;
}
// 立即返回future,不会被阻塞(等待线程执行结束)
CompletableFuture<String> future = completableFuture();
// join与get方法的目的一样,区别在于空值时get会抛出异常而join则会返回null,此时会阻塞 System.out.println(future.join());
// 输出:请开始你的表演...
hello World
——使用工厂类创建CompletableFuture对象,supplyAsync方法接收Supplier(提供者接口),并保存返回值
public CompletableFuture<String> completableFuture(String hello) {
return CompletableFuture.supplyAsync(() -> hello);
}
——thenCompose线程依赖性:线程B的执行需要线程A的结果值,其中B是同步执行,被阻塞
@Test
public void compose() {
// thenCompose方法接收Function参数,线程A的结果值以value形参传入B线程并返回一个CompletableFuture对象,对象中保存hello World结果值
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "hello").thenCompose(value -> CompletableFuture.supplyAsync(() -> value + " World"));
String result = future.join();
System.out.println("result = " + result);
}
// 输出:result = hello World
——thenCombine线程合并:线程A和线程B都执行结束后,各自返回一个值,使用BiFunction接口接收这两个结果并进行操作,A,B线程异步执行,B线程不会被阻塞
@Test
public void compose() {
// thenCombine接收CompletionStage和BiFunction参数,两个线程同时执行并返回v1,v2
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "hello").thenCombine(CompletableFuture.supplyAsync(() -> " world"), (v1, v2) -> v1 + v2);
String result = future.join();
System.out.println("result = " + result);
}
// 输出:result = hello world
流与线程的结合
@Test public void stream() { List<test.VcUser> list = Arrays.asList( new VcUser("demo1"), new VcUser("demo2"), new VcUser("demo3") ); // 自定义线程池,设定线程数量与集合长度取最小值,设定的线程数量并非越多越好,够用就行 final Executor executor = Executors.newFixedThreadPool(Math.min(list.size(), 10), runnable -> { Thread thread = new Thread(runnable); // 新建一个守护线程,防止 一个线程异常导致其他线程无法执行 thread.setDaemon(true); return thread; }); // 将集合通过流转化为用线程来处理数据(将同步转化为异步),提高执行效率,executor为自定义的线程池,注意!!!这里创建线程的时候并没有把函数执行完(只执行一部分),因此需要再次执行join或者get方法方可真正执行线程,千万别忘了
List<CompletableFuture<String>> futureList = list.stream().map(user -> CompletableFuture.supplyAsync(user::getName, executor)).collect(Collectors.toList());
List<String> stringList = futureList.stream().map(CompletableFuture::join).collect(Collectors.toList()); stringList.forEach(System.out::println); }
// 输出:demo1
demo2
demo3
注意!不可在线程创建后立即执行join或者get求值,否则将会导致同步执行,需先转化为CompletableFuture集合或者数组在求值
List<String> futureList = list.stream()
.map(user -> CompletableFuture.supplyAsync(user::getName, executor))
// 在转化成线程后最好不要直接求值,因为求值会使得线程阻塞,此时下一个线程转化则会需要上一个线程求值完之后才开始转化(被阻塞),因此会变成同步执行而非异步执行,执行所消耗的时长是累加的!!!
.map(CompletableFuture::join)
.collect(Collectors.toList());
allOf方法:所有线程执行都执行完
@Test
public void stream() {
List<test.VcUser> list = Arrays.asList(
new VcUser("demo1"),
new VcUser("demo2"),
new VcUser("demo3")
);
// 设定线程数量与集合长度取最小值,设定的线程数量并非越多越好,够用就行
final Executor executor = Executors.newFixedThreadPool(Math.min(list.size(), 10), runnable -> {
Thread thread = new Thread(runnable);
// 新建一个守护线程,防止 一个线程异常导致其他线程无法执行
thread.setDaemon(true);
return thread;
});
// 将集合转化为用线程来处理数据(将同步转化为异步),提高执行效率,executor为自定义的线程池
CompletableFuture[] futureList = list.stream()
.map(user -> CompletableFuture.supplyAsync(user::getName, executor))
// 将CompletableFuture集合转化为数据
.toArray(CompletableFuture[]::new);
CompletableFuture<Void> voids = CompletableFuture.allOf(futureList);
// 注意:这里会阻塞,需要等待所有线程执行完成
voids.join();
}
anyOf:只要有一个线程执行完即可,用法与allOf差不多