一、简介

  传统的Java多线程开发中,wait、notify、synchronized等如果不注意使用的话,很容易引起死锁、脏读问题。Java1.5 版本开始增加 java.util.concurrent 并发编程包,简化了多线程开发难度。添加了很多的多线程操作工具类,可根据实际需求去选择使用。

  JUC 常用工具类:

  Semaphore - 信号量

  ReentrantLock - 可重入锁。之前有做过简介使用,详见 https://www.cnblogs.com/eric-fang/p/8991208.html

  ReadWriteLock - 读写锁

  BlockingQueue - 阻塞队列。详见 https://www.cnblogs.com/eric-fang/p/8989860.html

  CountDownLatch - 计数器。在计数器归零后,允许之前阻塞的若干线程继续执行

  CyclicBarrier - 栅栏。在某一条件达成之前,所有线程均阻塞等待

  AtomicXXXXXXX - 原子操作类,常见的有:AtomicInteger、AtomicLong、AtomicBoolean。

  TimeUnit - 时间枚举类,提供一些时间的便捷操作

  Executor、ExecutorService、Future : 之前有做过简介使用,详见 https://www.cnblogs.com/eric-fang/p/9004020.html

二、使用

  2.1、信号量Semaphore

    一般用于限定同时访问操作的线程数量。例如:有时候可以很好的限制公共资源的使用,例如如果开启几十个线程去读取一些文件,然后读取到的数据需要入库的话,由于数据库的连接资源是稀缺资源,可能远小于读取文件的线程数,这时候可以利用信号量去限制每次并发获取数据库连接资源的线程数。

    如下示例代码,虽然同时有10个线程执行,但是只能允许2个线程的并发执行。

  1. package com.cfang.prebo.thread;
  2.  
  3. import java.util.concurrent.ExecutorService;
  4. import java.util.concurrent.Executors;
  5. import java.util.concurrent.Semaphore;
  6. import java.util.concurrent.TimeUnit;
  7.  
  8. import lombok.extern.slf4j.Slf4j;
  9.  
  10. @Slf4j
  11. public class TestSemaphore2 {
  12.  
  13. private static Semaphore semaphore = new Semaphore();
  14.  
  15. private static ExecutorService executorService = Executors.newFixedThreadPool();
  16.  
  17. public static void main(String[] args) {
  18. for(int i = ; i < ; i++) {
  19. executorService.execute(new Runnable() {
  20. @Override
  21. public void run() {
  22. try {
  23. //申请通行证
  24. semaphore.acquire();
  25. // 模拟业务逻辑
  26. TimeUnit.SECONDS.sleep();
  27. log.info("{} 处理完成", Thread.currentThread().getName());
  28. //释放通行证
  29. semaphore.release();
  30. } catch (InterruptedException e) {
  31. e.printStackTrace();
  32. }
  33. }
  34. });
  35. }
  36. executorService.shutdown();
  37. }
  38. }

  2.2、计数器CountDownLatch

    同步计数器,构造方法传值,用来限定计数器的次数。

    countDown方法每次调用,计数器值减 1。CountDownLatch会一直阻塞着调用await方法的线程,直到计数器值变为0。

  1. package com.cfang.prebo.thread;
  2.  
  3. import java.util.Random;
  4. import java.util.concurrent.CountDownLatch;
  5. import java.util.concurrent.TimeUnit;
  6. import java.util.concurrent.atomic.AtomicInteger;
  7.  
  8. import lombok.extern.slf4j.Slf4j;
  9.  
  10. @Slf4j
  11. public class TestCountDownLatch {
  12.  
  13. private static CountDownLatch countDownLatch = new CountDownLatch();
  14.  
  15. private static AtomicInteger integerVal = new AtomicInteger();
  16.  
  17. public static void main(String[] args) throws Exception{
  18. for(int i = ; i < ; i++) {
  19. new Thread(new Runnable() {
  20. @Override
  21. public void run() {
  22. //业务处理逻辑
  23. try {
  24. int size = new Random().nextInt();
  25. integerVal.getAndAdd(size);
  26. TimeUnit.SECONDS.sleep();
  27. log.info("{} 处理完成,{}", Thread.currentThread().getName(), size);
  28. } catch (InterruptedException e) {
  29. e.printStackTrace();
  30. }
  31. countDownLatch.countDown();
  32. }
  33. }, "thread-" + i).start();
  34. }
  35. String threadName = Thread.currentThread().getName();
  36. log.info("{} thread waiting...", threadName);
  37. countDownLatch.await();
  38. log.info("{} doing, value: {}",threadName, integerVal.get());
  39. }
  40.  
  41. }

  2.3、栅栏CyclicBarrier

  栅栏屏障,构造方法传值来设定一个阈值。线程调用 await 方法的时候,线程就会被阻塞。当阻塞的线程数达到阈值的时候,所有阻塞线程全部放行。可重置重复使用。

  1. package com.cfang.prebo.thread;
  2.  
  3. import java.util.Random;
  4. import java.util.concurrent.CyclicBarrier;
  5. import java.util.concurrent.TimeUnit;
  6. import java.util.concurrent.atomic.AtomicInteger;
  7.  
  8. import lombok.extern.slf4j.Slf4j;
  9.  
  10. @Slf4j
  11. public class TestCyclicBarrier implements Runnable{
  12.  
  13. private CyclicBarrier barrier = new CyclicBarrier(, this);
  14.  
  15. private static AtomicInteger integerVal = new AtomicInteger();
  16.  
  17. public void count() {
  18. for(int i = ; i < ; i++) {
  19. new Thread(new Runnable() {
  20. @Override
  21. public void run() {
  22. //业务处理逻辑
  23. try {
  24. int size = new Random().nextInt();
  25. integerVal.getAndAdd(size);
  26. TimeUnit.SECONDS.sleep();
  27. log.info("{} 处理完成,{}", Thread.currentThread().getName(), size);
  28. barrier.await();
  29. } catch (Exception e) {
  30. e.printStackTrace();
  31. }
  32. }
  33. }, "thread-" + i).start();
  34. }
  35. }
  36.  
  37. @Override
  38. public void run() {
  39. //业务逻辑处理完成后调用
  40. log.info("{} 统计完成,{}", Thread.currentThread().getName(), integerVal.get());
  41. }
  42.  
  43. public static void main(String[] args) {
  44. TestCyclicBarrier testCyclicBarrier = new TestCyclicBarrier();
  45. testCyclicBarrier.count();
  46. }
  47. }

JUC并发包基本使用的更多相关文章

  1. JUC并发包与容器类 - 面试题(一网打净,持续更新)

    文章很长,建议收藏起来,慢慢读! 疯狂创客圈为小伙伴奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 大厂必备 ...

  2. 聊聊 JUC 并发包

    今天开始我们聊聊 Java 并发工具包中提供的一些工具类,本文主要从并发同步容器和并发集合工具角度入手,简单介绍下相关 API 的用法与部分实现原理,旨在帮助大家更好的使用和理解 JUC 工具类. 在 ...

  3. JUC并发包学习

    1.什么是JUC java.util工具包.包.分类 业务:普通的线程代码 Thread Runable:没有返回值.效率相对于Callable相对较低. 2.线程和进程 进程:一个程序.如:QQ.e ...

  4. JUC——并发集合类

    如果要进行多个数据的保存,无疑首选类集(List.Set.Queue.Map),在类集的学习的时候也知道一个概念:许多集合的子类都具有同步与异步的差别,但是如果真的要在多线程之中去使用这些类,是否真的 ...

  5. 并发包学习(三)-AbstractQueuedSynchronizer总结

    J.U.C学习的第二篇AQS.AQS在Java并发包中的重要性,毋庸置疑,所以单独拿出来理一理.本文参考总结自<Java并发编程的艺术>第五章第二节队列同步器. 什么是AbstractQu ...

  6. JUC——JUC开发简介(一)

    前言 JUC是Java5.0开始提供的一组专门实现多线程并发处理的开发框架,利用JUC开发架构可以有效的解决实际线程项目开发之中出现的死锁.阻塞.资源访问与公平机制. 此笔记主要记录java.util ...

  7. Java并发包——线程通信

    Java并发包——线程通信 摘要:本文主要学习了Java并发包里有关线程通信的一些知识. 部分内容来自以下博客: https://www.cnblogs.com/skywang12345/p/3496 ...

  8. J.U.C并发包(1)

    J.U.C并发包(1) AbstractQueuedSynchronizer AbstractQueuedSynchronizer是JUC并发包中锁的底层支持,AbstractQueuedSynchr ...

  9. java架构之路(多线程)JUC并发编程之Semaphore信号量、CountDownLatch、CyclicBarrier栅栏、Executors线程池

    上期回顾: 上次博客我们主要说了我们juc并发包下面的ReetrantLock的一些简单使用和底层的原理,是如何实现公平锁.非公平锁的.内部的双向链表到底是什么意思,prev和next到底是什么,为什 ...

随机推荐

  1. MongoDB的分页排序

    我们已经学过MongoDB的 find() 查询功能了,在关系型数据库中的选取(limit),排序(sort) MongoDB中同样有,而且使用起来更是简单 首先我们看下添加几条Document进来 ...

  2. 【leetcode】581. Shortest Unsorted Continuous Subarray

    题目如下: 解题思路:本题我采用的是最简单最直接最粗暴的方法,把排序后的nums数组和原始数组比较即可得到答案. 代码如下: /** * @param {number[]} nums * @retur ...

  3. json对象之间的转化

    json字符串转化为 1.使用JSON.parse()函数 使用eval()函数 2.json对象转化为json字符串 使用JSON.stringify()

  4. clang和llvm的安装

    https://blog.csdn.net/qq_31157999/article/details/78906982

  5. vue的生产环境dependencies 和开发环境devDependencies,二者的理解和区别

  6. 2,Executor线程池

    一,Executor框架简介 在Java 5之后,并发编程引入了一堆新的启动.调度和管理线程的API.Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.co ...

  7. BP算法演示

    本文转载自https://mattmazur.com/2015/03/17/a-step-by-step-backpropagation-example/ Background Backpropaga ...

  8. GeoServer-2.12安装MbTiles扩展插件

  9. 如何快速优雅的解决:ORA-02290: 违反检查约束条件 异常问题

    在向oracle保存数据时,控制台报错如下: 很明显是保存时,该表的设计不允许某个字段非空导致的,但由于该表的数量较多,采用断点的方式有太过麻烦, 这里笔者采用 oracle 的客户端连接工具orac ...

  10. Mysql中主键与索引

    摘自: https://www.cnblogs.com/wicub/p/5898286.html 一.什么是索引?索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存.如果没 ...