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个线程可以同时访问数据库连接保存数据,否则会报错无法连接数据库异常。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • java web在高并发和分布式下实现订单号生成唯一的解决方案

    方案一: 如果没有并发,订单号只在一个线程内产生,那么由于程序是顺序执行的,不同订单的生成时间戳正常不同,因此用时间戳+随机数(或自增数)就可以区分各个订单.如果存在并发,且订单号是由一个进程中的多个线程产生的,那么只要把线程ID添加到序列号中就可以保证订单号唯一.如果存在并发,且订单号是由同一台主机中的多个进程产生的,那么只要把进程ID添加到序列号中就可以保证订单号唯一.如果存在并发,且订单号是由不同台主机产生的,那么MAC地址.IP地址或CPU序列号等能够区分主机的号码添加到序列号中就可以保

  • java 并发编程之共享变量的实现方法

    可见性 如果一个线程对共享变量值的修改, 能够及时的被其他线程看到, 叫做共享变量的可见性. Java 虚拟机规范试图定义一种 Java 内存模型 (JMM), 来屏蔽掉各种硬件和操作系统的内存访问差异, 让 Java 程序在各种平台上都能达到一致的内存访问效果. 简单来说, 由于 CPU 执行指令的速度是很快的, 但是内存访问的速度就慢了很多, 相差的不是一个数量级, 所以搞处理器的那群大佬们又在 CPU 里加了好几层高速缓存. 在 Java 内存模型里, 对上述的优化又进行了一波抽象. JM

  • java高并发锁的3种实现示例代码

    初级技巧 - 乐观锁 乐观锁适合这样的场景:读不会冲突,写会冲突.同时读的频率远大于写. 以下面的代码为例,悲观锁的实现: public Object get(Object key) { synchronized(map) { if(map.get(key) == null) { // set some values } return map.get(key); } } 乐观锁的实现: public Object get(Object key) { Object val = null; if((

  • Java常见面试题之多线程和高并发详解

    volatile 对 volatile的理解 volatile 是一种轻量级的同步机制. 保证数据可见性 不保证原子性 禁止指令重排序 JMM JMM(Java 内存模型)是一种抽象的概念,描述了一组规则或规范,定义了程序中各个变量的访问方式. JVM运行程序的实体是线程,每个线程创建时 JVM 都会为其创建一个工作内存,是线程的私有数据区域.JMM中规定所有变量都存储在主内存,主内存是共享内存.线程对变量的操作在工作内存中进行,首先将变量从主内存拷贝到工作内存,操作完成后写会主内存.不同线程间

  • Java并发之BlockingQueue的使用

    本文主要讲的是并发包中涉及到的集合,关于普通集合,请参考[java 集合概览] 一.什么是BlockingQueue BlockingQueue即阻塞队列,从阻塞这个词可以看出,在某些情况下对阻塞队列的访问可能会造成阻塞.被阻塞的情况主要有如下两种: 1. 当队列满了的时候进行入队列操作 2. 当队列空了的时候进行出队列操作 因此,当一个线程试图对一个已经满了的队列进行入队列操作时,它将会被阻塞,除非有另一个线程做了出队列操作:同样,当一个线程试图对一个空队列进行出队列操作时,它将会被阻塞,除非

  • 详解java解决分布式环境中高并发环境下数据插入重复问题

    java 解决分布式环境中 高并发环境下数据插入重复问题 前言 原因:服务器同时接受到的重复请求 现象:数据重复插入 / 修改操作 解决方案 : 分布式锁 对请求报文生成 摘要信息 + redis 实现分布式锁 工具类 分布式锁的应用 package com.nursling.web.filter.context; import com.nursling.nosql.redis.RedisUtil; import com.nursling.sign.SignType; import com.nu

  • 详细分析Java并发集合ArrayBlockingQueue的用法

    在上一章中,我们介绍了阻塞队列BlockingQueue,下面我们介绍它的常用实现类ArrayBlockingQueue. 一. 用数组来实现队列 因为队列这种数据结构的特殊要求,所以它天然适合用链表的方式来实现,用两个变量分别记录链表头和链表尾,当删除或插入队列时,只要改变链表头或链表尾就可以了,而且链表使用引用的方式链接的,所以它的容量几乎是无限的. 那么怎么使用数组来实现队列,我们需要四个变量:Object[] array来存储队列中元素,headIndex和tailIndex分别记录队列

  • Java并发工具辅助类代码实例

    java中的并发工具类 一:等待多线程完成的CountDownLatch CountDownLatch允许一个或多个线程等待其他线程完成操作. package com.fuzhulei; import java.util.concurrent.*; ​ /** * 减法计数器,主要是countDown(计数器1) 和 await(阻塞)方法,只有当计数器减为0的时候,当前线程才可以往下继续执行. * 主要用于允许一个或多个线程等待其他线程完成操作 * @author Huxudong * @cr

  • java实体对象与Map之间的转换工具类代码实例

    这篇文章主要介绍了java实体对象与Map之间的转换工具类代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Map接口中键和值一一映射. 可以通过键来获取值. 给定一个键和一个值,你可以将该值存储在一个Map对象. 之后,你可以通过键来访问对应的值. 当访问的值不存在的时候,方法就会抛出一个NoSuchElementException异常. 当对象的类型和Map里元素类型不兼容的时候,就会抛出一个 ClassCastException异常

  • 了解JAVA并发工具常用设计套路

    前言 在学习JAVA并发工具时,分析JUC下的源码,发现有三个利器:状态.队列.CAS. 状态 一般是state属性,如AQS源码中的状态,是整个工具的核心,一般操作的执行都要看当前状态是什么, 由于状态是多线程共享的,所以都是volatile修饰,保证线程直接内存可见. /** * AbstractQueuedSynchronizer中的状态 */ private volatile int state; /** * Status field, taking on only the values

  • Java并发工具类Exchanger的相关知识总结

    一.Exchanger的理解 Exchanger 属于java.util.concurrent包: Exchanger 是 JDK 1.5 开始提供的一个用于两个工作线程之间交换数据的封装工具类; 一个线程在完成一定的事务后想与另一个线程交换数据,则第一个先拿出数据的线程会一直等待第二个线程,直到第二个线程拿着数据到来时才能彼此交换对应数据. 二.Exchanger类中常用方法 public Exchanger() 无参构造方法.表示创建一个新的交换器. public V exchange(V

  • Java并发工具类Future使用示例

    目录 前言 Future使用示例 FutureTask 前言 Future是一个接口类,定义了5个方法: boolean cancel(boolean mayInterruptIfRunning); boolean isCancelled(); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws Interrupte

  • 使用jquery 的ajax 与 Java servlet的交互代码实例

    这篇文章主要介绍了使用jquery 的ajax 与 Java servlet的交互代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 由于是使用jquery的 所以别忘记导入jq 下面是jsp文件 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!

  • Java程序生成Access文件代码实例

    这篇文章主要介绍了Java程序生成Access文件代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 package access; import java.io.File; import java.io.IOException; import java.sql.SQLException; import java.sql.Types; import org.junit.Test; import com.healthmarketscience

  • java 读取系统Properties代码实例

    这篇文章主要介绍了java 读取系统Properties代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 java读取系统Properties 属性,针对配置较多的属性值,单独打印,实现代码如下: import java.util.*; public class PropertiesTest { public static void main(String[] args) { Properties properties = System.

  • Java递归遍历文件目录代码实例

    这篇文章主要介绍了Java递归遍历文件目录代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在读取文件降序输出单词及其个数的基础上,将txt文件存入文件夹中,开始递归遍历文件目录,之后输出txt文件中的单词及其个数,仍然是降序排列. 代码如下 import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.util.Map

  • python基于gevent实现并发下载器代码实例

    这篇文章主要介绍了python基于gevent实现并发下载器代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 并发下载原理 import gevent from gevent import monkey import urllib.request monkey.patch_all() def my_download(url): print('GET: %s' % url) resp = urllib.request.urlopen(url

随机推荐