1、初识线程
官方概念:线程是指进程中的一个执行流程,一个进程中可以运行多个线程。本人对于线程的理解:jvm作为一个非常大的公司,员工(线程)为了完成一个一个的工作而产生的一条条执行的路线。但是这些工作都是为了完成一个总的工作,所以在jvm的总调度下进行工作。所以在调度中心的调度下有条不紊的进行着自己的工作。
2、在原始的开发工作中能够遇到的场景。
在进行接口调用的时候,被调用的接口可能需要处理一些和返回数据关系不大的逻辑(比如:记录一下这个接口的日志、需要下载一个附件)。如果要等这些逻辑处理完的话可能会花费很长的时间去处理,可能导致调用此接口时等待时间长,影响接口调用时间的优化。可能采用的方法,采用一个匿名线程的方式进行处理此业务。(正在进行业务操作的主线程和声明的这个匿名线程互不影响,但是无法知道匿名线程的结果以及不知道匿名线程是否会出现异常)
new Thread() {
public void run() {
synchronized (this) {
System.out.println("启动新线程去下载附件");
System.out.println("启动新线程去记录日志");
}
}
;
}.start();
3、线程池的方式进行线程的管理
CountDownLatch是通过一个计数器来实现的,计数器的初始化值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就相应得减1。当计数器到达0时,表示所有的线程都已完成任务,然后在闭锁上等待的线程就可以恢复执行任务。
举一个现实中例子就是:CountDownLatch 就像跑步比赛中的裁判,三个方法就是就是三位运动员,运动员2,3都已经到达终点,但是运动员1摔倒了,动不了。裁判员只看到两位运动员到达终点不能宣布比赛结束,所以一直等。。。
就像这样的场景导致线上service执行线程阻塞,接口调用次数累计导致dubbo线程满了
//声明一个固定的线程池的数量
private static ExecutorService executorService = Executors.newFixedThreadPool(10);
//声明一个已经被消费掉的线程数用来计数
private CountDownLatch countDownLatch;
//业务代码
countDownLatch = new CountDownLatch(list.size());
executorService.submit(() -> {
try {
//TODO 这里调用处理类
} catch (Exception e) {
} finally {
countDownLatch.countDown();
}
//等待所有数据处理完
countDownLatch.await();
4、使用competablefuture进行线程的管理
使用场景一、当一个接口需要去访问多个不同的接口或者处理多个并行的业务的时候。
需要特别说明一下里面的异常处理机制:使用
exceptionally ,在方法内部声明一个匿名函数,第一个参数为异常类型,第二个参数为返回值类型。
CompletableFuture<String> cf_yjs = CompletableFuture.supplyAsync(() -> {
String yjs_result = HttpUtil.doPostJson(netzwdtyjsrest_url, params);
return yjs_result;
}).exceptionally(new Function<Throwable, String>() {
@Override
public String apply(Throwable throwable) {
System.out.println("异常:" + throwable.getMessage());
return JsonUtils.zwdtRestReturn("1", "查询失败!", "");
}
});
cf_yjs.join();
使用场景二、当前线程需要使用另外一个线程的接口当做入参进行业务操作
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
return "业务完成,返回参数";
}).thenCompose(dish -> {
return CompletableFuture.supplyAsync(() -> {
return dish + " 完成";
});
});
/**
* 如果没发生异常
* A 和 B 并发执行
* B 执行完后执行 C
*
* 如果发生异常,立刻返回异常
* 代码中有3段注释,模拟 发生异常的情况
*/
public class ExceptionImmediatelyReturn {
public static void main(String[] args) {
try {
String result = getABCResult();
SmallTool.printTimeAndThread(result);
} catch (Exception e) {
SmallTool.printTimeAndThread("发生异常 " + e.getMessage());
e.printStackTrace();
}
}
private static String getABCResult() {
CompletableFuture<String> a = CompletableFuture.supplyAsync(() -> {
SmallTool.printTimeAndThread("start A");
SmallTool.sleepMillis(1000);
// if (true) {
// throw new RuntimeException("a error");
// }
SmallTool.printTimeAndThread("end A");
return "A";
});
CompletableFuture<String> bAndC = CompletableFuture.supplyAsync(() -> {
SmallTool.printTimeAndThread("start B");
SmallTool.sleepMillis(2000);
// if (true) {
// throw new RuntimeException("b error");
// }
SmallTool.printTimeAndThread("end B");
return "B";
}).thenCompose(resultB -> CompletableFuture.supplyAsync(() -> {
SmallTool.printTimeAndThread("start C");
SmallTool.sleepMillis(1000);
// if (true) {
// throw new RuntimeException("c error");
// }
SmallTool.printTimeAndThread("end C");
return resultB + " C";
}));
List<CompletableFuture> cfList = new LinkedList<>();
cfList.add(a);
cfList.add(bAndC);
while (cfList.size() > 0) {
CompletableFuture.anyOf(cfList.toArray(new CompletableFuture[cfList.size()])).join();
cfList.removeIf(completableFuture -> completableFuture.isDone());
}
/**
* 拼装结果
*/
return "正常执行完毕 -->" + a.join() + " " + bAndC.join();
}
}
SmallTool.printTimeAndThread("小白和小伙伴们 进餐厅点菜");
long startTime = System.currentTimeMillis();
ArrayList<Dish> dishes = new ArrayList<>();
// 点菜
for (int i = 1; i <= 10; i++) {
Dish dish = new Dish("菜" + i, 1);
dishes.add(dish);
}
// 做菜
for (Dish dish : dishes) {
CompletableFuture.runAsync(() -> dish.make()).join();
}
SmallTool.printTimeAndThread("菜都做好了,上桌 " + (System.currentTimeMillis() - startTime));
}
SmallTool.printTimeAndThread("小白和小伙伴们 进餐厅点菜");
long startTime = System.currentTimeMillis();
// 点菜
ArrayList<Dish> dishes = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
Dish dish = new Dish("菜" + i, 1);
dishes.add(dish);
}
// 做菜
ArrayList<CompletableFuture> cfList = new ArrayList<>();
for (Dish dish : dishes) {
CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> dish.make());
cfList.add(cf);
}
// 等待所有任务执行完毕
CompletableFuture.allOf(cfList.toArray(new CompletableFuture[cfList.size()])).join();
SmallTool.printTimeAndThread("菜都做好了,上桌 " + (System.currentTimeMillis() - startTime));
//-Djava.util.concurrent.ForkJoinPool.common.parallelism=8
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "12");
SmallTool.printTimeAndThread("小白和小伙伴们 进餐厅点菜");
long startTime = System.currentTimeMillis();
CompletableFuture[] dishes = IntStream.rangeClosed(1, 12)
.mapToObj(i -> new Dish("菜" + i, 1))
.map(dish -> CompletableFuture.runAsync(dish::make))
.toArray(size -> new CompletableFuture[size]);
CompletableFuture.allOf(dishes).join();
SmallTool.printTimeAndThread("菜都做好了,上桌 " + (System.currentTimeMillis() - startTime));
// Returns the number of processors available to the Java virtual machine
System.out.println(Runtime.getRuntime().availableProcessors());
// 查看 当前线程数
System.out.println(ForkJoinPool.commonPool().getPoolSize());
// 查看 最大线程数
System.out.println(ForkJoinPool.getCommonPoolParallelism());
ExecutorService threadPool = Executors.newCachedThreadPool();
SmallTool.printTimeAndThread("小白和小伙伴们 进餐厅点菜");
long startTime = System.currentTimeMillis();
CompletableFuture[] dishes = IntStream.rangeClosed(1, 12)
.mapToObj(i -> new Dish("菜" + i, 1))
.map(dish -> CompletableFuture.runAsync(dish::makeUseCPU, threadPool))
.toArray(size -> new CompletableFuture[size]);
CompletableFuture.allOf(dishes).join();
threadPool.shutdown();
SmallTool.printTimeAndThread("菜都做好了,上桌 " + (System.currentTimeMillis() - startTime));
ThreadPoolExecutor executor = new ThreadPoolExecutor(0, Integer.MAX_VALUE,
0, TimeUnit.MILLISECONDS,
new SynchronousQueue<Runnable>());
CompletableFuture.runAsync(() -> SmallTool.printTimeAndThread("A"), executor)
.thenRunAsync(() -> SmallTool.printTimeAndThread("B"), executor)
.join();