多线程创建方式 线程池、Future和CompletableFuture

大家好,我是烤鸭:

     今天说一下 多线程的几种创建方式及使用。

1. Thread 和 Runnable


    继承 Thread 类 和实现 Runnable 接口。
    这种就不举例子了。

2.线程池


  现在主要有5种线程池。

  //缓存线程池
  ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); 
  //固定大小线程池
  ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);
  //单线程执行
  ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
  //定时或延迟执行
  ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);
  //窃取线程池
  ExecutorService workStealingPool = Executors.newWorkStealingPool();

其中 newWorkStealingPool 是jdk 1.8以后新出的,为了防止线程池启用过多,导致cpu占用过多导致的项目宕机。适用于执行多任务,且每个任务耗时时间较短。
  其余4种方式都有可能会出现占用cpu过高导致的项目宕机的情况。
  以 4核 16G的机器为例, Executors.newFixedThreadPool(10) 这种方式创建的线程池大小为10
  Executors.newWorkStealingPool() 创建线程池大小为4。一般来说,和核数相等
  即便不使用这种方式,也建议不要超过 核数 * 2。(具体看需求)


3. Future和CompletableFuture


Future 是 jdk1.5 以后出现的,用于异步多线程。
例子:

// 创建Future集合,用于存放完成的Future
List<Future<Long>> futureList = new ArrayList();
//多线程执行任务
for (int i = 0; i < 100; i++) {
    Future<Long> testFuture= workStealingPool.submit(new Callable<Long>() {
        @Override
        public Long call() {
            //模拟执行耗时任务
            System.out.println("task 1 doing...");
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return 0L;
        }
    });
    futureList.add(testFuture);
}
//遍历list,获取线程结果
for (Future<Long> taskResponseFuture: futureList) {
    if(taskResponseFuture.get().equals(0L)){
        //当前future执行完毕
    }
}

这里注意一下,Future.get()是阻塞方法。如果需要多线程执行操作,在最后的时候执行get()方法。
类似上边的例子,可以把 多个 Future 放到list中,再循环get。

CompletableFuture 是 Future的实现类,关于异步多线程提供了更多的api,下面介绍几种常用的。


supplyAsync 异步执行,有返回值

CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(() -> {
  //模拟执行耗时任务
  System.out.println("task 1 doing...");
  try {
      Thread.sleep(1000);
  } catch (Exception e) {
      e.printStackTrace();
  }
  //返回结果
  return 0;
});

thenAccept 接收上一阶段的输出作为本阶段的输入。多线程(单个线程)的顺序执行。

completableFuture1.thenApply(new Function<Integer, Object>() {
    @Override
    public Object apply(Integer integer) {
        //模拟执行耗时任务
        System.out.println("task thenApply doing...");
        try {
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }
});

whenComplete 异步监听结果

completableFuture1.whenComplete(new BiConsumer<Integer,Throwable>() {
    @Override
    public void accept(Integer o, Throwable o2) {
        if(o == 0L){
            System.out.println("task complete...");
        }else{
            throw new RuntimeException();
        }
    }
});
发布了115 篇原创文章 · 获赞 58 · 访问量 23万+

猜你喜欢

转载自blog.csdn.net/Angry_Mills/article/details/88624776