Java高并发专题之34、谷歌提供的一些好用的并发工具类

关于并发方面的,juc已帮我们提供了很多好用的工具,而谷歌在此基础上做了扩展,使并发编程更容易,这些工具放在guava.jar包中。

本文演示几个简单的案例,见一下guava的效果。

guava maven配置

  1. <dependency>
  2. <groupId>com.google.guava</groupId>
  3. <artifactId>guava</artifactId>
  4. <version>27.0-jre</version>
  5. </dependency>

guava中常用几个类

MoreExecutors:提供了一些静态方法,是对juc中的Executors类的一个扩展。
Futures:也提供了很多静态方法,是对juc中Future的一个扩展。

案例1:异步执行任务完毕之后回调

  1. package com.itsoku.chat34;
  2. import com.google.common.util.concurrent.ListenableFuture;
  3. import com.google.common.util.concurrent.ListeningExecutorService;
  4. import com.google.common.util.concurrent.MoreExecutors;
  5. import lombok.extern.slf4j.Slf4j;
  6. import java.util.concurrent.ExecutionException;
  7. import java.util.concurrent.ExecutorService;
  8. import java.util.concurrent.Executors;
  9. import java.util.concurrent.TimeUnit;
  10. /**
  11. * 跟着阿里p7学并发,微信公众号:javacode2018
  12. */
  13. @Slf4j
  14. public class Demo1 {
  15. public static void main(String[] args) throws ExecutionException, InterruptedException {
  16. //创建一个线程池
  17. ExecutorService delegate = Executors.newFixedThreadPool(5);
  18. try {
  19. ListeningExecutorService executorService = MoreExecutors.listeningDecorator(delegate);
  20. //异步执行一个任务
  21. ListenableFuture<Integer> submit = executorService.submit(() -> {
  22. log.info("{}", System.currentTimeMillis());
  23. //休眠2秒,默认耗时
  24. TimeUnit.SECONDS.sleep(2);
  25. log.info("{}", System.currentTimeMillis());
  26. return 10;
  27. });
  28. //当任务执行完毕之后回调对应的方法
  29. submit.addListener(() -> {
  30. log.info("任务执行完毕了,我被回调了");
  31. }, MoreExecutors.directExecutor());
  32. log.info("{}", submit.get());
  33. } finally {
  34. delegate.shutdown();
  35. }
  36. }
  37. }

输出:

  1. 14:25:50.055 [pool-1-thread-1] INFO com.itsoku.chat34.Demo1 - 1567491950047
  2. 14:25:52.063 [pool-1-thread-1] INFO com.itsoku.chat34.Demo1 - 1567491952063
  3. 14:25:52.064 [pool-1-thread-1] INFO com.itsoku.chat34.Demo1 - 任务执行完毕了,我被回调了
  4. 14:25:52.064 [main] INFO com.itsoku.chat34.Demo1 - 10

说明:

ListeningExecutorService接口继承于juc中的ExecutorService接口,对ExecutorService做了一些扩展,看其名字中带有Listening,说明这个接口自带监听的功能,可以监听异步执行任务的结果。通过MoreExecutors.listeningDecorator创建一个ListeningExecutorService对象,需传递一个ExecutorService参数,传递的ExecutorService负责异步执行任务。

ListeningExecutorServicesubmit方法用来异步执行一个任务,返回ListenableFutureListenableFuture接口继承于juc中的Future接口,对Future做了扩展,使其带有监听的功能。调用submit.addListener可以在执行的任务上添加监听器,当任务执行完毕之后会回调这个监听器中的方法。

ListenableFutureget方法会阻塞当前线程直到任务执行完毕。

上面的还有一种写法,如下:

  1. package com.itsoku.chat34;
  2. import com.google.common.util.concurrent.*;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.checkerframework.checker.nullness.qual.Nullable;
  5. import java.util.concurrent.ExecutionException;
  6. import java.util.concurrent.ExecutorService;
  7. import java.util.concurrent.Executors;
  8. import java.util.concurrent.TimeUnit;
  9. /**
  10. * 跟着阿里p7学并发,微信公众号:javacode2018
  11. */
  12. @Slf4j
  13. public class Demo2 {
  14. public static void main(String[] args) throws ExecutionException, InterruptedException {
  15. ExecutorService delegate = Executors.newFixedThreadPool(5);
  16. try {
  17. ListeningExecutorService executorService = MoreExecutors.listeningDecorator(delegate);
  18. ListenableFuture<Integer> submit = executorService.submit(() -> {
  19. log.info("{}", System.currentTimeMillis());
  20. TimeUnit.SECONDS.sleep(4);
  21. //int i = 10 / 0;
  22. log.info("{}", System.currentTimeMillis());
  23. return 10;
  24. });
  25. Futures.addCallback(submit, new FutureCallback<Integer>() {
  26. @Override
  27. public void onSuccess(@Nullable Integer result) {
  28. log.info("执行成功:{}", result);
  29. }
  30. @Override
  31. public void onFailure(Throwable t) {
  32. try {
  33. TimeUnit.MILLISECONDS.sleep(100);
  34. } catch (InterruptedException e) {
  35. e.printStackTrace();
  36. }
  37. log.error("执行任务发生异常:" + t.getMessage(), t);
  38. }
  39. }, MoreExecutors.directExecutor());
  40. log.info("{}", submit.get());
  41. } finally {
  42. delegate.shutdown();
  43. }
  44. }
  45. }

输出:

  1. 14:26:07.938 [pool-1-thread-1] INFO com.itsoku.chat34.Demo2 - 1567491967936
  2. 14:26:11.944 [pool-1-thread-1] INFO com.itsoku.chat34.Demo2 - 1567491971944
  3. 14:26:11.945 [main] INFO com.itsoku.chat34.Demo2 - 10
  4. 14:26:11.945 [pool-1-thread-1] INFO com.itsoku.chat34.Demo2 - 执行成功:10

上面通过调用Futures的静态方法addCallback在异步执行的任务中添加回调,回调的对象是一个FutureCallback,此对象有2个方法,任务执行成功调用onSuccess,执行失败调用onFailure

失败的情况可以将代码中int i = 10 / 0;注释去掉,执行一下可以看看效果。

示例2:获取一批异步任务的执行结果

  1. package com.itsoku.chat34;
  2. import com.google.common.util.concurrent.Futures;
  3. import com.google.common.util.concurrent.ListenableFuture;
  4. import com.google.common.util.concurrent.ListeningExecutorService;
  5. import com.google.common.util.concurrent.MoreExecutors;
  6. import lombok.extern.slf4j.Slf4j;
  7. import java.util.ArrayList;
  8. import java.util.List;
  9. import java.util.concurrent.*;
  10. import java.util.stream.Collectors;
  11. /**
  12. * 跟着阿里p7学并发,微信公众号:javacode2018
  13. */
  14. @Slf4j
  15. public class Demo3 {
  16. public static void main(String[] args) throws ExecutionException, InterruptedException {
  17. log.info("star");
  18. ExecutorService delegate = Executors.newFixedThreadPool(5);
  19. try {
  20. ListeningExecutorService executorService = MoreExecutors.listeningDecorator(delegate);
  21. List<ListenableFuture<Integer>> futureList = new ArrayList<>();
  22. for (int i = 5; i >= 0; i--) {
  23. int j = i;
  24. futureList.add(executorService.submit(() -> {
  25. TimeUnit.SECONDS.sleep(j);
  26. return j;
  27. }));
  28. }
  29. //获取一批任务的执行结果
  30. List<Integer> resultList = Futures.allAsList(futureList).get();
  31. //输出
  32. resultList.forEach(item -> {
  33. log.info("{}", item);
  34. });
  35. } finally {
  36. delegate.shutdown();
  37. }
  38. }
  39. }

输出:

  1. 14:26:35.970 [main] INFO com.itsoku.chat34.Demo3 - star
  2. 14:26:41.137 [main] INFO com.itsoku.chat34.Demo3 - 5
  3. 14:26:41.138 [main] INFO com.itsoku.chat34.Demo3 - 4
  4. 14:26:41.138 [main] INFO com.itsoku.chat34.Demo3 - 3
  5. 14:26:41.138 [main] INFO com.itsoku.chat34.Demo3 - 2
  6. 14:26:41.138 [main] INFO com.itsoku.chat34.Demo3 - 1
  7. 14:26:41.138 [main] INFO com.itsoku.chat34.Demo3 - 0

结果中按顺序输出了6个异步任务的结果,此处用到了Futures.allAsList方法,看一下此方法的声明:

  1. public static <V> ListenableFuture<List<V>> allAsList(
  2. Iterable<? extends ListenableFuture<? extends V>> futures)

传递一批ListenableFuture,返回一个ListenableFuture<List<V>>,内部将一批结果转换为了一个ListenableFuture对象。

示例3:一批任务异步执行完毕之后回调

异步执行一批任务,最后技术其和

  1. package com.itsoku.chat34;
  2. import com.google.common.util.concurrent.*;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.checkerframework.checker.nullness.qual.Nullable;
  5. import java.util.ArrayList;
  6. import java.util.List;
  7. import java.util.concurrent.ExecutionException;
  8. import java.util.concurrent.ExecutorService;
  9. import java.util.concurrent.Executors;
  10. import java.util.concurrent.TimeUnit;
  11. /**
  12. * 跟着阿里p7学并发,微信公众号:javacode2018
  13. */
  14. @Slf4j
  15. public class Demo4 {
  16. public static void main(String[] args) throws ExecutionException, InterruptedException {
  17. log.info("star");
  18. ExecutorService delegate = Executors.newFixedThreadPool(5);
  19. try {
  20. ListeningExecutorService executorService = MoreExecutors.listeningDecorator(delegate);
  21. List<ListenableFuture<Integer>> futureList = new ArrayList<>();
  22. for (int i = 5; i >= 0; i--) {
  23. int j = i;
  24. futureList.add(executorService.submit(() -> {
  25. TimeUnit.SECONDS.sleep(j);
  26. return j;
  27. }));
  28. }
  29. ListenableFuture<List<Integer>> listListenableFuture = Futures.allAsList(futureList);
  30. Futures.addCallback(listListenableFuture, new FutureCallback<List<Integer>>() {
  31. @Override
  32. public void onSuccess(@Nullable List<Integer> result) {
  33. log.info("result中所有结果之和:" + result.stream().reduce(Integer::sum).get());
  34. }
  35. @Override
  36. public void onFailure(Throwable t) {
  37. log.error("执行任务发生异常:" + t.getMessage(), t);
  38. }
  39. }, MoreExecutors.directExecutor());
  40. } finally {
  41. delegate.shutdown();
  42. }
  43. }
  44. }

输出:

  1. 14:47:04.819 [main] INFO com.itsoku.chat34.Demo4 - star
  2. 14:47:09.933 [pool-1-thread-1] INFO com.itsoku.chat34.Demo4 - result中所有结果之和:15

代码中异步执行了一批任务,所有任务完成之后,回调了上面的onSuccess方法,内部对所有的结果进行sum操作。

总结

  • 通过guava提供的一些工具类,方便异步执行任务并进行回调

  • guava内部还有很多好用的工具类,有兴趣的可以去研究一下

来源:http://itsoku.com/course/1/34

posted @ 2022-05-04 23:38  程序员小明1024  阅读(81)  评论(0编辑  收藏  举报