编辑
2022-12-21
学习记录
00

前言😚

以前需要异步执行一个任务时,一般是用Thread或者线程池Executor去创建。如果需要返回值,则是调用Executor.submit获取Future。但是多个线程存在依赖组合,我们又能怎么办?可使用同步组件CountDownLatch、CyclicBarrier等;其实有简单的方法,就是用CompeletableFuture

  • 线程任务的创建
  • 线程任务的串行执行
  • 线程任务的并行执行
  • 处理任务结果和异常
  • 多任务的简单组合
  • 取消执行线程任务
  • 任务结果的获取和完成与否判断

1 创建异步线程任务

根据supplier创建CompletableFuture任务

java
//使用内置线程ForkJoinPool.commonPool(),根据supplier构建执行任务 public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) //指定自定义线程,根据supplier构建执行任务 public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)

根据runnable创建CompletableFuture任务

java
//使用内置线程ForkJoinPool.commonPool(),根据runnable构建执行任务 public static CompletableFuture<Void> runAsync(Runnable runnable) //指定自定义线程,根据runnable构建执行任务 public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
  • 使用示例
java
ExecutorService executor = Executors.newSingleThreadExecutor(); CompletableFuture<Void> rFuture = CompletableFuture .runAsync(() -> System.out.println("hello siting"), executor); //supplyAsync的使用 CompletableFuture<String> future = CompletableFuture .supplyAsync(() -> { System.out.print("hello "); return "siting"; }, executor); //阻塞等待,runAsync 的future 无返回值,输出null System.out.println(rFuture.join()); //阻塞等待 String name = future.join(); System.out.println(name); executor.shutdown(); // 线程池需要关闭 --------输出结果-------- hello siting null hello siting
编辑
2022-12-15
学习记录
00

什么是并行流?

简单来说,并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。 Java 8 中将并行进行了优化,我们可以很容易的对数据进行并行操作。 Stream API 可以声明性地通过 parallel() 与sequential() 在并行流与顺序流之间进行切换 。

Fork/Join 框架

Fork/Join 框架: 就是在必要的情况下,将一个大任务,进行拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个的小任务运算的结果进行 join 汇总 。

Fork/Join 框架与传统线程池有啥区别?

采用 “工作窃取”模式(work-stealing):

当执行新的任务时它可以将其拆分成更小的任务执行,并将小任务加到线程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中。

相对于一般的线程池实现,fork/join框架的优势体现在对其中包含的任务的处理方式上。在一般的线程池中,如果一个线程正在执行的任务由于某些原因无法继续运行,那么该线程会处于等待状态。而在fork/join框架的实现中,如果某个子任务由于等待另外一个子任务的完成而无法继续运行。那么处理该子问题的线程会主动寻找其他尚未运行的子任务来执行。这种方式减少了线程的等待时间,提高了程序的性能。

编辑
2022-12-13
学习记录
00

为什么要使用lambda表达式(函数式接口)

  • 避免匿名内部类定义过多
  • 可以让你的代码看起来更简洁
  • 保留核心的逻辑
  • 函数式接口定义:一个接口中只有唯一一个的抽象方法

lambda 表达式总结:

  • 总结lambda只能在只有一行的情况下才能简化为一行
  • 前提是接口为函数式接口
  • 多个参数,也能去掉类型,必须加上括号

编辑
2022-12-13
学习记录
00

java实现多线程的方式有三种

第一种继承thread 类,重写run方法调用

继承thread类具备多线程的能力 启动线程 子类对象.start() 不建议使用:避免面向对象单继承的局限性

第二种就是实现runnable接口

重写run方法实现 实现接口runnable具备多线程 能力 启动线程 传入目标对+threa对象.start() 推荐使用:避免单继承的局限性,灵活方便,方便同一个对象被多个线程调用

第三种就是实现callable接口

重写call方法,创建线程池,把对象加入到线程池中 启用线程,最后关闭线程池

编辑
2022-12-13
学习记录
00

提示

线程有五种状态:创建、就绪、运行、阻塞、结束

结束(stop)

//线程正常停止 //使用标志位 //不要使用stop,destroy

public class TestStop implements Runnable { private boolean flag=true; @Override public void run() { int i=0; while (flag){ System.out.println("run thread"+i++); } } public void stop(){ this.flag=false; } public static void main(String[] args) { TestStop testStop=new TestStop(); new Thread(testStop).start(); for (int i = 0; i < 1000; i++) { System.out.println("main"+i); if (i==900){ testStop.stop(); System.out.println("线程停止"); } } } }

线程休眠(sleep)

指定当前线程阻塞的毫秒数 存在异常interruptionException 时间到达后进入就绪状态 sleep模拟网络延迟