• java中的并发工具辅助类


    java中的并发工具类

    一:等待多线程完成的CountDownLatch

    CountDownLatch允许一个或多个线程等待其他线程完成操作。

    package com.fuzhulei;
    import java.util.concurrent.*;

    /**
    * 减法计数器,主要是countDown(计数器1) 和 await(阻塞)方法,只有当计数器减为0的时候,当前线程才可以往下继续执行。
    * 主要用于允许一个或多个线程等待其他线程完成操作
    * @author Huxudong
    * @createTime 2020-04-05 00:04:36
    **/
    public class CountDownDemo {
      public static void main(String[] args) throws InterruptedException {
          /** 使用其构造函数,创建一个数值为6的计数器 */
          CountDownLatch countDownLatch = new CountDownLatch(6);
          /** 自定义线程池使用 */
          ExecutorService pool = new ThreadPoolExecutor(
                  6,   // 核心线程池大小
                  9, // 最大线程池的大小(根据是IO密集型,还是CPU密集型来确定大小)
                  3L,   // 超时等待时间
                  TimeUnit.SECONDS,   // 时间的单位
                  new LinkedBlockingQueue<>(5), // 阻塞队列是哪一种
                  Executors.defaultThreadFactory(),     // 默认线程创建工厂
                  new ThreadPoolExecutor.AbortPolicy()   // 四大拒绝策略,选择一种
          );
          try{
              for (int i = 0; i < 6; i++) {
                  /** 这个线程的提交,没有返回值的任务 */
                  pool.execute(()->{
                      countDownLatch.countDown();
                      System.out.println(Thread.currentThread().getName()+"执行一次减法");
                  });

              }
          } catch(Exception e) {
              e.printStackTrace();
          } finally {
              /** 关闭线程池 */
              pool.shutdown();
          }

          countDownLatch.await();
          System.out.println("执行完成了");

      }
    }

    正确执行结果:

     

    但是如果我们设置计数器的容量大于6的话(相对于我的程序而言),就会被阻塞在那里

     

    会发现 执行完成了 没有被打印出来,而且程序一直没有停止,这个时候就是因为计数器没有归0,所以当前线程被阻塞,不能向下面继续进行。

     

    二:同步屏障CyclicBarrier

    CyclicBarrier的翻译大致就是可循环的屏障。它主要的作用就是让一组线程到达一个屏障(也可以叫做同步点)时被阻塞,直到最后一份线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。

    package com.fuzhulei;

    import java.util.concurrent.BrokenBarrierException;
    import java.util.concurrent.CyclicBarrier;

    /**
    * CyclicBarrier是一个加法计数器,即同步屏障,可循环的屏障,让一组线程到达一个屏障(也可以叫做同步点)时被阻塞,直到最后一个线程到达屏障,达到了一开始初始化的屏障的数值,
    * 屏障才可以打开门,所有被拦截的线程才可以继续工作,主要是通过调用await方法来实现的
    * @author Huxudong
    * @createTime 2020-04-04 22:53:50
    **/
    public class CyclicBarrierDemo {
      public static void main(String[] args) {
          CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
          new Thread(()->{

              try {
                  cyclicBarrier.await();
              } catch (InterruptedException e) {
                  e.printStackTrace();
              } catch (BrokenBarrierException e) {
                  e.printStackTrace();
              }
              System.out.println("线程A已经到达屏障");
          },"A").start();

          new Thread(()->{
              try {
                  cyclicBarrier.await();
              } catch (InterruptedException e) {
                  e.printStackTrace();
              } catch (BrokenBarrierException e) {
                  e.printStackTrace();
              }
              System.out.println("线程B已经到达屏障");
          },"B").start();

          new Thread(()->{
              try {
                  cyclicBarrier.await();
              } catch (InterruptedException e) {
                  e.printStackTrace();
              } catch (BrokenBarrierException e) {
                  e.printStackTrace();
              }
              System.out.println("线程C已经到达屏障");
          },"C").start();


      }
    }

    执行的结果如下:

     

    但是如果把定义的容量大于3(相对于我的程序而言),就会发现什么都不会输出了,看截图

     

    并且程序一直还没有停止,这就是屏障起到了作用,因为屏障要求至少需要4个(假设),但是此时只有三个线程到达,所以不满足,屏障就一直阻拦不放路,那么所有的线程也就被阻塞不能向下面继续运行,除非知道第四个过来,满足条件才会运行。

     

    三:控制并发线程数的Semaphore

    用来控制同时访问特定资源的线程数量,通过协调各个线程,以保证合理的使用公用的资源。

    package com.fuzhulei;

    import java.util.concurrent.*;

    /**
    * 用来控制同时访问特定资源的线程数量,通过协调各个线程,以保证合理的使用公用的资源
    * @author Huxudong
    * @createTime 2020-04-04 23:45:29
    **/
    public class SemaphoreDemo {
      public static void main(String[] args) {
          Semaphore semaphore = new Semaphore(5);
          ExecutorService pool = new ThreadPoolExecutor(
                  10,
                  20,
                  3L,
                  TimeUnit.SECONDS,
                  new LinkedBlockingQueue<>(20),
                  Executors.defaultThreadFactory(),
                  new ThreadPoolExecutor.AbortPolicy());

          try{
              for (int i = 0; i < 60; i++) {
                  pool.execute(() ->{
                      try {
                          semaphore.acquire();
                          System.out.println(Thread.currentThread().getName()+"限流成功");
                          semaphore.release();
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                  });
              }
          } catch(Exception e) {
              e.printStackTrace();
          } finally {
              pool.shutdown();
          }
      }
    }

    执行的结果如下:

     

    例如:数据库资源,假如需要读取几十万个数据的文件,因为都是IO密集型任务,所以开了2倍的处理器+1个线程数(IO密集型,所以线程可以多一些,让cpu忙起来,因为IO操作的时候,很少操作Cpu)

    但是如果读到内存后,还需要存储到数据库中,但是数据库连接我们设置的加入就10个,所以我们必须控制只有10个线程可以同时访问数据库连接保存数据,否则会报错无法连接数据库异常。

  • 相关阅读:
    [数据结构与算法 01] 什么是数据结构?什么是算法?联系是什么?常用的数据结构/算法有?
    程序员面试金典-面试题 16.05. 阶乘尾数
    程序员面试金典-面试题 16.04. 井字游戏
    程序员面试金典-面试题 16.02. 单词频率
    程序员面试金典-面试题 16.01. 交换数字
    程序员面试金典-面试题 10.11. 峰与谷
    程序员面试金典-面试题 10.10. 数字流的秩
    程序员面试金典-面试题 10.09. 排序矩阵查找
    程序员面试金典-面试题 10.05. 稀疏数组搜索
    程序员面试金典-面试题 10.03. 搜索旋转数组
  • 原文地址:https://www.cnblogs.com/clover-forever/p/12635506.html
Copyright © 2020-2023  润新知