JUC(java.util.concurrent)处理并发编程工具包

  1. 线程的创建方式
  • 继承Thread

    package thread.ThreadCreate;
    public class ExtendThread {
          
          
        public static void main(String[] args) {
          
          
            System.out.println("main...start...");
            Thread thread = new Thread01();
            thread.start();
            System.out.println("main...end...");
        }
        public static class Thread01 extends Thread{
          
          
            @Override
            public void run(){
          
          
                System.out.println("当前线程:" + Thread.currentThread().getId());
                int i = 11 / 2;
                System.out.println("执行结果:" + i);
            }
        }
    }
    

在这里插入图片描述

  • 实现Runnable

    package thread.ThreadCreate;
    public class ImplementRunnable {
          
          
        public static void main(String[] args) {
          
          
            System.out.println("main...start...");
            Runnable runnable = new Runnable01();
            new Thread(runnable).start();
            System.out.println("main...end...");
        }
        public static class Runnable01 implements Runnable{
          
          
            @Override
            public void run(){
          
          
                System.out.println("当前线程:" + Thread.currentThread().getId());
                int i = 11 / 2;
                System.out.println("执行结果:" + i);
            }
        }
    }
    

在这里插入图片描述

  • 实现Callable+通过FutureTask执行线程

    package thread.ThreadCreate;
    import java.util.concurrent.*;
    
    public class ThreadPool {
          
          
        public static void main(String[] args) throws ExecutionException, InterruptedException {
          
          
            System.out.println("main...start...");
            ExecutorService service = Executors.newFixedThreadPool(10);
            // 无返回值
            service.execute(new Runnable01());
            // 有返回值
            Future<Integer> future = service.submit(new Callable01());
            Integer result = future.get();
            System.out.println("main...end..." + result);
        }
        public static class Runnable01 implements Runnable{
          
          
            @Override
            public void run(){
          
          
                System.out.println("当前线程:" + Thread.currentThread().getId());
                int i = 11 / 2;
                System.out.println("执行结果:" + i);
            }
        }
        public static class Callable01 implements Callable<Integer> {
          
          
            @Override
            public Integer call() throws Exception {
          
          
                System.out.println("当前线程:" + Thread.currentThread().getId());
                int i = 11 / 2;
                System.out.println("执行结果:" + i);
                return i;
            }
        }
    }
    
  1. 线程池七大参数
  • corePoolSize(核心线程数)
    创建好以后就准备就绪的线程数量.除非设置了allowCoreThreadTimeOut,否则会一直存在
  • maximumPoolSize(最大线程数量)
    能够创建的最大线程数量,用以控制资源.
  • keepAliveTime(线程池中空闲线程等待工作的超时时间)
    如果当前线程数大于核心线程数,并且线程空闲时间大于keepAliveTime,则会释放空闲线程,但会保证释放后的线程数大于等于核心线程数.
  • TimeUnit unit(时间单位)
    即keepAliveTime的时间单位
  • BlockingQueue workQueue(堵塞队列)
    当任务很多时,没有更多的线程去执行,那么多的任务就会放在堵塞队列中,只要有线程空闲,就从堵塞队列中取出新的任务执行.
  • ThreadFactory(线程创建工厂)
  • RejectedExecutionHandler handler(拒绝执行任务处理器)
    如果堵塞队列满了,就按照指定的拒绝策略拒绝执行任务
  1. 线程池的执行顺序
  • 线程池创建,准备core数量的核心线程,准备接收任务
  • 当core满了,再进来的任务就会放入到堵塞队列中.空闲的核心线程会去堵塞队列中获取任务执行
  • 如果堵塞队列也满了,则创建新线程执行,最大只能创建指定的maximumPoolSize数量.
  • 如果堵塞队列满了,并且线程池也开到了最大线程数,那么就使用RejectedExecutionHandler拒绝执行任务
  • 如果创建了多于核心线程数的线程,并且空闲,则在keepAliveTime时间后释放多余空闲的线程.
  1. 一个线程池,core:7,max:20,queue50,100个并发进行怎么执行
  • 7个任务占用7个核心线程会立刻执行
  • 50个任务放入堵塞队列中
  • 再开13个线程执行任务
  • 剩余的30个并发任务使用拒绝策略
  1. 常见的四种线程池
  • newCachedThreadPool(可缓存线程池)
    如果线程池长度超过处理需要,可灵活回收空闲线程(只要线程空闲,所有线程都可回收),如果线程不够用于执行任务,则创建新的线程去执行.
    本质上是调用原生的ThreadPoolExecutor方法(核心线程数为0, 最大线程数为Integer.MAX_VALUE).
  • newFixedThreadPool(固定数量线程池)
    核心线程数和最大线程数相等.所有线程都不可回收
    本质上调用原生的ThreadPoolExecutor方法.
  • newScheduledThreadPool(定时任务线程池)
  • newSingleThreadExecutor(单线程的线程池)
    后台从队列中获取任务,挨个执行
    本质上是调用原生的ThreadPoolExecutor方法(核心线程数和最大线程数都为1).
  1. 开发中为什么使用线程池
  • 降低资源消耗
    通过重复利用已经创建好的线程降低线程创建和销毁带来的损耗
  • 提高响应速度
    有的线程可能处于等待分配任务的状态,当任务来时无须创建新的线程就能执行
  • 提高线程的可管理性
    线程池会根据当前系统特点对池内的线程进行优化处理,减少创建和销毁线程带来的系统开销.无限的创建和销毁线程不仅消耗系统资源,还会降低系统的稳定性,使用线程池进行统一分配.
  1. CompletableFuture异步编排
  • CompletableFuture的使用

    package thread.ThreadCreate;
    import java.util.concurrent.CompletableFuture;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class CompletableFutureUse {
          
          
    	// 创建一个大小为10的固定大小线程池,
        public static ExecutorService executor = Executors.newFixedThreadPool(10);
        public static void main(String[] args) throws ExecutionException, InterruptedException {
          
          
            System.out.println("main...start...");
            // runAsync没有返回值
            CompletableFuture<Void> future = CompletableFuture.runAsync(()->{
          
          
                System.out.println("当前线程:" + Thread.currentThread().getId());
                int i = 11 /2;
                System.out.println("运行结果:" + i);
            }, executor);
    
            // supplyAsync有返回结果
            CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(()->{
          
          
                System.out.println("当前线程:" + Thread.currentThread().getId());
                int i = 11 /2;
                System.out.println("运行结果:" + i);
                return i;
            }, executor).whenComplete((res, exception)->{
          
          
                // whenComplete可以处理正常和异常的计算结果,但是没有返回值
                System.out.println("异步任务成功完成。。结果是:" + res + "异常是:" + exception);
            }).exceptionally(exception->{
          
          
                // exceptionally,处理异常,返回一个异常情况下的默认值
                System.out.println("异常是:" + exception);
                return 10;
            });
            System.out.println("main...end..." + completableFuture.get());
        }
    }
    
  • 计算完成时的回调方法

    • whenComplete: 处理正常和异常情况下的计算结果,但是没有返回值.执行当前任务的线程继续执行whenComplete的任务.
    • whenCompleteAsync: 执行whenCompleteAsync的任务提交给线程池来执行,如果使用的是同一个线程池,也有可能被同一个线程执行.
    • exceptionally: 处理异常情况,返回一个默认值
  • handle(异步任务执行完后的处理)

    CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(()->{
          
          
                System.out.println("当前线程:" + Thread.currentThread().getId());
                int i = 11 / 2;
                System.out.println("运行结果:" + i);
                return i;
            }, executor).handle((res, throwable)->{
          
          
                if(res != null){
          
          
                    return res * 2;
                }
                if(throwable != null){
          
          
                    return 0;
                }
                return 0;
            });
    
  • 线程串形化

    • thenRun: 不能获得上一步的执行结果,无返回值

      CompletableFuture<Void> completableFuture2 = CompletableFuture.supplyAsync(()->{
              
              
                  System.out.println("当前线程:" + Thread.currentThread().getId());
                  int i = 11 / 2;
                  System.out.println("运行结果:" + i);
                  return i;
              }, executor).thenRun(()->{
              
              
                  System.out.println("任务2启动了");
              });
      
    • thenRunAsync: 不能获得上一步的执行结果,无返回值.执行thenRunAsync的任务提交给线程池来执行

      CompletableFuture<Void> completableFuture2 = CompletableFuture.supplyAsync(()->{
              
              
                  System.out.println("当前线程:" + Thread.currentThread().getId());
                  int i = 11 / 2;
                  System.out.println("运行结果:" + i);
                  return i;
              }, executor).thenRunAsync(()->{
              
              
                  System.out.println("任务2启动了");
              },executor);
      
    • thenAcceptAsync: 能接受上一步结果,但是无返回值

      CompletableFuture<Void> completableFuture3 = CompletableFuture.supplyAsync(()->{
              
              
                  System.out.println("当前线程:" + Thread.currentThread().getId());
                  int i = 11 / 2;
                  System.out.println("运行结果:" + i);
                  return i;
              }, executor).thenAcceptAsync((res)->{
              
              
                  System.out.println("任务2启动了");
                  System.out.println("上一个任务的返回结果为:" + res);
              },executor);
      
    • thenApplyAsync: 既能接受上一步的结果,也有返回值

      CompletableFuture<Integer> completableFuture4 = CompletableFuture.supplyAsync(()->{
              
              
                  System.out.println("当前线程:" + Thread.currentThread().getId());
                  int i = 11 / 2;
                  System.out.println("运行结果:" + i);
                  return i;
              }, executor).thenApplyAsync((res)->{
              
              
                  System.out.println("任务2启动了");
                  System.out.println("上一个任务的返回结果为:" + res);
                  return res * res;
              },executor);
              System.out.println("main...end..." + completableFuture4.get());
      
  • 两任务组合-都要完成

    • thenCombine: 组合两个future,获取两个future的返回结果,并返回当前任务的返回值

      CompletableFuture<Integer> task1 = CompletableFuture.supplyAsync(()->{
              
              
          System.out.println("当前线程:" + Thread.currentThread().getId());
          int i = 11 / 2;
          System.out.println("任务1结束");
          return i;
      }, executor);
      CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(()->{
              
              
          System.out.println("当前线程:" + Thread.currentThread().getId());
          int i = 3 / 2;
          System.out.println("任务2结束");
          return i;
      }, executor);
      CompletableFuture<String> task3 = task1.thenCombineAsync(task2,(t1, t2)->{
              
              
          System.out.println("任务3开始...任务1和任务2的结果分别为:" + t1 + "=>" + t2);
          return "task3";
      });
      
    • thenAcceptBoth: 组合两个future,获取两个future的返回结果,然后处理任务,没有返回值

      System.out.println("测试两任务组合。。。");
              CompletableFuture<Integer> task1 = CompletableFuture.supplyAsync(()->{
              
              
                  System.out.println("当前线程:" + Thread.currentThread().getId());
                  int i = 11 / 2;
                  System.out.println("任务1结束");
                  return i;
              }, executor);
              CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(()->{
              
              
                  System.out.println("当前线程:" + Thread.currentThread().getId());
                  int i = 3 / 2;
                  System.out.println("任务2结束");
                  return i;
              }, executor);
              task1.thenAcceptBothAsync(task2,(t1, t2)->{
              
              
                  System.out.println("任务3开始...任务1和任务2的结果分别为:" + t1 + "=>" + t2);
              });
      
    • runAfterBoth: 组合两个future,不需要获取future的结果,只需要两个future处理完任务后,处理该任务

      CompletableFuture<Integer> task1 = CompletableFuture.supplyAsync(()->{
              
              
                  System.out.println("当前线程:" + Thread.currentThread().getId());
                  int i = 11 / 2;
                  System.out.println("任务1结束");
                  return i;
              }, executor);
              CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(()->{
              
              
                  System.out.println("当前线程:" + Thread.currentThread().getId());
                  int i = 3 / 2;
                  System.out.println("任务2结束");
                  return i;
              }, executor);
              task1.runAfterBothAsync(task2,()->{
              
              
                  System.out.println("任务3开始");
              });
      
  • 两任务组合-一个完成

    • applyToEither: 两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值
    • acceptEither: 两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值
    • runAfterEither: 两个任务有一个执行完成,不需要获取future的结果,处理任务,也没有返回值
  • 多任务组合

    • allOf(所有任务都要执行成功)

      CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(()->{
              
              
                  System.out.println("查询商品的图片信息");
                  return "hello.jpg";
              }, executor);
              CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(()->{
              
              
                  System.out.println("查询商品的属性信息");
                  return "黑色+256G";
              }, executor);
              CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(()->{
              
              
                  try {
              
              
                      Thread.sleep(1000);
                      System.out.println("查询商品的描述信息");
                  } catch (InterruptedException e) {
              
              
                      e.printStackTrace();
                  }
                  return "苹果13";
              }, executor);
              CompletableFuture<Void> allof = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
              // 作用是等待所有结果完成,否则由于异步,可能先执行其他操作
              allof.get();
      
    • anyOf(只要有一个任务执行成功即可)
      代码与allOf类似

猜你喜欢

转载自blog.csdn.net/qq_26496077/article/details/115022714
今日推荐