文章插图
JAVA并发工具类主要有CyclicBarrier、CountDownLatch、Semaphore和Exchanger,日常开发中经常使用的是CountDownLatch和Semaphore 。下面就简单分析下这几个并发工具类:
CyclicBarrier 内存屏障CyclicBarrier底层借助于一个count计数器和Lock/Condition实现内存内存屏障功能,在对count--时必须先获取到lock,如果count不为0,则调用condition.wait进行阻塞操作;直到当count为0时,执行barrierCommand(如果配置的话,执行barrierCommand的线程是刚好将count减到0的那个线程),然后调用condition.signalAll唤醒所有等待的线程 。
CyclicBarrier可用于多线程同步、多线程计算最后合并计算结果的场景,比如分片计算最后使用CyclicBarrier统计最后的结果等 。CyclicBarrier使用示例如下:
public static void main(String[] args) throws Exception { CyclicBarrier barrier = new CyclicBarrier(2, () -> System.out.println(Thread.currentThread().getName() + ": all is ok")); Runnable task = () -> { try { System.out.println(Thread.currentThread().getName() + ": start wait"); barrier.await(); System.out.println(Thread.currentThread().getName() + ": start ok"); } catch (Exception e) { e.printStackTrace(); } }; Thread t1 = new Thread(task, "thread1"); Thread t2 = new Thread(task, "thread2"); t2.start(); t1.start(); t1.join(); t2.join();}
CountDownLatch 计数器CountDownLatch允许一个或多个线程等待其他线程完成操作 。CountDownLatch底层借助于AQS来实现功能,初始化一个CountDownLatch(n)时,相当于创建了一个state为n的AQS,当调用countDown()时会对AQS进行减一操作,如果state为0,则会对阻塞队列中所有线程进行唤醒操作 。CountDownLatch计数器必须大于等于0,等于0的时候调用await方法时不会阻塞当前线程,注意CountDownLatch不可能重新初始化或者修改CountDownLatch对象的内部计数的值 。一个线程调用coundDown方法hAppen-before,另一个线程调用await方法 。
public static void main(String[] args) throws Exception { CountDownLatch downLatch = new CountDownLatch(2); Runnable task = () -> { try { System.out.println(Thread.currentThread().getName() + ": start countDown"); downLatch.countDown(); System.out.println(Thread.currentThread().getName() + ": start ok"); } catch (Exception e) { e.printStackTrace(); } }; Thread t1 = new Thread(task, "thread1"); Thread t2 = new Thread(task, "thread2"); t1.start(); t2.start(); downLatch.await(); System.out.println("main wait ok"); t1.join(); t2.join();}
Semaphore信号量Semaphore用来控制同时访问特定资源的线程数量,它通过协调各个线程,保证合理的使用公共资源 。Semaphore可用作流量控制,特别是公共资源有限的应用场景,比如数据库连接 。Semaphore底层也是基于AQS,初始化Semaphore(n)相当于初始化一个state为n的AQS,调用acquire()时会对进行state - 1操作,如果结果大于0则CAS设置state为state-1,相当于获取到了信号量,否则进行阻塞操作(调用tryAcquire则不会阻塞线程) 。调用release会对state进行++操作 。
推荐阅读
- gradle:现代高效的java构建工具
- Go 并发编程的思考
- JavaScript?可视化:js引擎
- 10个 JavaScript 开发技巧,前端新手非常有必要掌握
- JetBrains 2020 年开发者生态系统状况报告,JAVA 最受欢迎的语言
- 快来学,那些关于燃气灶你不知道的事
- 淘宝创意标题怎么设置的 淘宝关于制作标题的注意事项
- Java类加载机制实现流程及原理详解
- 国内 Java 开发者必备的两个装备,你配置上了么?
- 关于头条号新版后台向万粉创作者开放内测的通知