前言

一文读懂java多线程下常用常考的阻塞方法LongAdder、CountDownLatch、CyclicBarrier、Phaser
包含演示代码

高并发模拟,性能比较实例代码

  • 前言
  • LongAdder
  • synchronized VS Atomic Vs LongAdder
  • CountDownLatch
  • CyclicBarrier
  • Phaser

LongAdder

在高并发下LongAdder是如何工作的?

LongAdder采用了分段锁的概念,在高并发下,如果是连续递增,这LongAdder会分成几块进行递增然后再相加,从而提高效率


synchronized VS Atomic Vs LongAdder

在高并发下 synchronized VS Atomic Vs LongAdder谁的效率更高?

这是不一定的,需要看具体的应用场景和数据量

synchronized 是通过加锁保证了线程同步,相对来说效率要低一些

Atomic 类中都是原子操作,可以称之为无锁优化,底层通过unsafe实现,不能完全保证线程安全性
unsafe 是java很底层的一个类,里面大多直接调用了native(本地)方法实现。
我们不能直接看到,unsafe可以直接操作指针,内存。之前版本还可以调用出来使用,现在应该是不可以使用了

LongAdder 内部采用了分段锁的概念,就是在高并发自增的情况下,可以分出来几块自增,然后进行相加,从而提高效率

下面代码模拟1000线程,没有线程操作100000次,
synchronized VS Atomic Vs LongAdder 那个效率更高

package 线程同步LongAdder;import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;/*** @program: solution* @description: LongAdder内部类似与分段锁,如果发现多个相同(比如递增的操作)* 它会分几块递增然后相加操作。* 所以在并发量很高的情况下,效率高于synchronized和atomic*在一千个线程每个线程操作十万次的情况下,效率对比* synchronized VS Atomic Vs LongAdder* @author: Wang Hai Xin* @create: 2022-11-08 10:17**/
public class testLongAdder {static Long count1 = 0L;static AtomicLong count2 = new AtomicLong(0);static LongAdder count3 = new LongAdder();public static void main(String[] args) throws InterruptedException {Thread[] threads = new Thread[1000];/*synchronized*/Object lock = new Object();for (int i = 0; i < threads.length; i++) {threads[i] = new Thread(()->{for (int j = 0; j < 100000; j++)synchronized (lock){count1++;}});}long start = System.currentTimeMillis();for (Thread thread : threads) {thread.start();}for (Thread thread : threads) {try {thread.join();} catch (InterruptedException e) {throw new RuntimeException(e);}}long end = System.currentTimeMillis();System.out.println("syn: " + count1 + " time: " + (end - start));
/*Atomic*/start = System.currentTimeMillis();for (int i = 0; i < threads.length; i++) {threads[i] = new Thread(()->{for (int j = 0; j < 100000; j++) {count2.incrementAndGet();}});}for (Thread thread : threads) {thread.start();}for (Thread thread : threads) {thread.join();}end = System.currentTimeMillis();System.out.println("Atomic: " + count2.get() + " time: " + (end - start));
/*LongAdder*/start = System.currentTimeMillis();for (int i = 0; i < threads.length; i++) {threads[i] = new Thread(()->{for (int i1 = 0; i1 < 100000; i1++) {count3.increment();}});}for (Thread thread : threads) {thread.start();}for (Thread thread : threads) {thread.join();}end = System.currentTimeMillis();System.out.println("LongAdder: " + count3.longValue() + " time: " + (end - start));}}

运行结果

syn: 100000000 time: 4198
Atomic: 100000000 time: 2322
LongAdder: 100000000 time: 259

注意并不是说LongAdder一定比其它两个效率高,只能是在特定条件下。

CountDownLatch

CountDownLatch 作用和jion()方法类似,像一个门栓,调用CountDownLatch.countDown()就会减一
当减少到0之后线程会继续运行。是一个阻塞的方法。

CountDownLatch 主要用在一个线程等待多个线程的情况下使用

代码如下


package ReentrantLock和LongAdder;import java.util.concurrent.CountDownLatch;/*** @program: solution* @description: CountDownLatch 使用演示* @author: Wang Hai Xin* @create: 2022-11-10 15:29**/
public class CountDownT {public static void main(String[] args) {CountDownT countDownT = new CountDownT();countDownT.usingCountDowm();countDownT.usingJion();}public void usingCountDowm(){Thread[] threads = new Thread[100];CountDownLatch countDownLatch = new CountDownLatch(threads.length);for (int i = 0; i < threads.length; i++) {threads[i] = new Thread(()->{int result = 0;for (int i1 = 0; i1 < 10000; i1++) {result++;}countDownLatch.countDown();});}for (int i = 0; i < threads.length; i++) {threads[i].start();}try {countDownLatch.await();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("end latch");}public void usingJion(){Thread[] threads = new Thread[100];CountDownLatch countDownLatch = new CountDownLatch(threads.length);for (int i = 0; i < threads.length; i++) {threads[i] = new Thread(()->{int result = 0 ;for (int i1 = 0; i1 < 10000; i1++) {result++;}countDownLatch.countDown();});}for (int i = 0; i < threads.length; i++) {threads[i].start();}for (int i = 0; i < threads.length; i++) {try {threads[i].join();} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("end join");}}

运行结果

end latch
end join

CyclicBarrier

CyclicBarrier 也是一个阻塞的方法,不过与countDownLatch不同,CyclicBarrier类似与一个起跑线。当数量够了之后,一起起跑。

CyclicBarrier 用在多个线程相互等待的场景

如下代码 ,我们在创建的时候规定,满20个线程,执行程序。不满20个 就会阻塞在这里

package ReentrantLock和LongAdder;import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;/*** @program: solution* @description: CycliBarrier 用法演示* @author: Wang Hai Xin* @create: 2022-11-10 15:48**/
public class CyclicBarrierT {public static void main(String[] args) {CyclicBarrier cyclicBarrier = new CyclicBarrier(20, new Runnable() {@Overridepublic void run() {System.out.println("满20人 ,发车");}});for (int i = 0; i < 100; i++) {new Thread(()->{try {cyclicBarrier.await();} catch (InterruptedException e) {throw new RuntimeException(e);} catch (BrokenBarrierException e) {throw new RuntimeException(e);}}).start();}}
}

Phaser

phaser 类似与周期性的CyclicBarrier, 可以通过构造函数或者使用 phaser.bulkRegister(7);注册

现在我们模拟一个结婚的场景,必须所有人到场才能吃饭,所有人离席 新郎新娘才能抱抱

代码演示如下:

package ReentrantLock和LongAdder;import 线程同步volatile单例.T;import java.util.concurrent.Phaser;
import java.util.concurrent.TimeUnit;/*** @program: solution* @description: Phaser 演示代码,Phaser用于分段阻塞* @author: Wang Hai Xin* @create: 2022-11-11 09:49**/
public class PhaserT {static  PhaserDemo phaser = new PhaserDemo();public static void main(String[] args) {phaser.bulkRegister(7);for (int i = 0; i < 5; i++) {final  int name = i;new Thread(new Person("p"+i)).start();}new Thread(new Person("新郎")).start();new Thread(new Person("新娘")).start();}static class PhaserDemo extends Phaser  {/*参数 phase 表示第几个周期,registeredParties表示这个周期注册的线程数*/@Overrideprotected boolean onAdvance(int phase, int registeredParties) {switch (phase){case 0 :{System.out.println("所有人到场"+registeredParties);return false;}case 1:{System.out.println("所有人吃完"+registeredParties);return false;}case 2 :{System.out.println("所有人离场"+registeredParties);return false;}case 3 : {System.out.println("新郎新娘抱抱"+registeredParties);return true;}default:{return true;}}}}static class Person implements Runnable {public String name = null;public Person(String s) {name = s;}/*睡眠方法*/void milliSleep(){try {TimeUnit.MILLISECONDS.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}}public void arrive(){milliSleep();System.out.printf( "%s 到达现场! \n",name);System.out.println();/*注册Phaser*/phaser.arriveAndAwaitAdvance();}public void eat(){milliSleep();System.out.printf("%s 开始吃饭",name);System.out.println();phaser.arriveAndAwaitAdvance();}public void leave(){milliSleep();System.out.printf("%s 离开",name);System.out.println();phaser.arriveAndAwaitAdvance();}public void hug(){milliSleep();if ("新郎".equals(name) || "新娘".equals(name)) {System.out.printf("%s 洞房",name);System.out.println();phaser.arriveAndAwaitAdvance();}else{/*不是新郎新娘不可以进入洞房,这里注销掉,注销掉仍然算是一个线程到达*/phaser.arriveAndDeregister();}}@Overridepublic void run() {arrive();eat();leave();hug();}}
}

运行结果

p1 到达现场!
p3 到达现场! p2 到达现场! p4 到达现场! 新郎 到达现场! 新娘 到达现场! p0 到达现场! 所有人到场7
p2 开始吃饭
p1 开始吃饭
新郎 开始吃饭
p3 开始吃饭
p0 开始吃饭
p4 开始吃饭
新娘 开始吃饭
所有人吃完7
p1 离开
p2 离开
p3 离开
p4 离开
新娘 离开
p0 离开
新郎 离开
所有人离场7
新郎 洞房新娘 洞房新郎新娘抱抱2进程已结束,退出代码0

java多线程下LongAdder、CountDownLatch、CyclicBarrier、Phaser 的用法相关推荐

  1. Java多线程下载网图

    Java多线程下载网图案例 此案例依赖--文件操作工具类(FileUtils) 使用 apache 的commons-io包下的FileUtilsimportorg.apache.commons.io ...

  2. Java多线程并发控制工具CountDownLatch,实现原理及案例

    跟着作者的65节课彻底搞懂Java并发原理专栏,一步步彻底搞懂Java并发原理. 作者简介:笔名seaboat,擅长工程算法.人工智能算法.自然语言处理.架构.分布式.高并发.大数据和搜索引擎等方面的 ...

  3. JAVA多线程下高并发的处理经验

    java中的线程:java中,每个线程都有一个调用栈存放在线程栈之中,一个java应用总是从main()函数开始运行,被称为主线程.一旦创建一个新的线程,就会产生一个线程栈.线程总体分为:用户线程和守 ...

  4. 《Java 7 并发编程指南》学习概要 (3)Semaphore, CountDownLatch, CyclicBarrier , Phaser, Exchanger...

    1.Semaphore  信号量 Semaphore(信号量)是一个控制访问多个共享资源的计数器. 当一个线程想要访问某个共享资源,首先,它必须获得semaphore.如果semaphore的内部计数 ...

  5. (面经总结)一篇文章带你完整复习 Java 中并发关键字(CountDownLatch/CyclicBarrier/Semaphore/Volatile)

    文章目录 一.倒计数器:CountDownLatch 二.循环栅栏:CyclicBarrier 三.信号量:Semaphore 四.volatile 关键字的作用 一.倒计数器:CountDownLa ...

  6. Java 多线程之闭锁-CountDownLatch

    实现并发的最直接方式是在操作系统级别使用进程.进程是运行在自己的地址空间内的自包容程序.多任务操作系统可以通过周期性地将CPU从一个进程切换到另一个进程,来实现同时运行多个进程的.操作系统将进程相互隔 ...

  7. java多线程——Executors线程池的四种用法简单解析

    1.Executors.newFixedThreadPool(5)    是创建一个线程池,池子里面有5个线程,任务数多余5个时,超出的任务队列中排队等候执行 2.Executors.newCache ...

  8. Android 价值千万java多线程同步 lt;五CountDownLatch(计数器)和Semaphore(信号量)

    1).Android 价值千万   java线程专题:Wait&notify&join&Yield http://blog.csdn.net/whb20081815/artic ...

  9. java多线程学习-java.util.concurrent详解

    http://janeky.iteye.com/category/124727 java多线程学习-java.util.concurrent详解(一) Latch/Barrier 博客分类: java ...

最新文章

  1. 1380 没有上司的舞会
  2. 关于flink的日志文件设置
  3. 毫秒值转换为日期工具_为机器学习准备数据
  4. nginx学习笔记003---Nginx代理配置_注意,在Windows中路径要用/
  5. 中秋海报设计素材|中秋节海报文案
  6. ACdream - 1073 雷霆战机
  7. 数仓之事实表和维度表(一)
  8. 芯烨打印机api密钥php,php连接芯烨云打印机 (php demo)
  9. ICE java实现helloworld
  10. fatal: unable to access ...: LibreSSL SSL_connnect: Connection reset by peer in connect to... :443
  11. 如何重设或更改Verizon FIOS路由器的密码
  12. 可以几分钟快速对接支付宝APP支付和手机网站支付?
  13. 雷电html查看程序编辑程序,雷电模拟器应用操作
  14. 写出HTML的基本结构 做简要说明,北京市顺义区2017年--2018年届高三二模语文试题(卷)与答案解析.doc...
  15. 3.7V锂电池电压与容量关系
  16. 次世代zbrush骷颅头高模雕刻 艺术头骨SP模型材质贴图讲解
  17. qnap刷android tv,【威联通 TAS-268 电视NAS使用总结】连接|界面|应用|性能_摘要频道_什么值得买...
  18. js如何转换json字符串,js如何转换为数值型
  19. 由于 Windows 无法加载这个设备所需的驱动程序,导致这个设备工作异常。 (代码 31)”
  20. java输出希腊字母_java 命令行窗口输出希腊字母表

热门文章

  1. Elasticsearch和MySQL数据同步(logstash-input-jdbc)全量增量方式同步近千万数据
  2. QT时间相关的使用(日期相减问题)
  3. 官宣:2021年计算机技术与软件考试工作安排及报名时间等说明
  4. The Standalone Programmer: Tips from the trenches(1)
  5. @Pointcut 使用
  6. Elasticsearch和springboot版本对应
  7. 三相交流参数稳压电源,三相交流电源稳压器
  8. python二进制十进制转化
  9. SpringMvc :Ajax技术
  10. 计算机硬盘的分区表结构布局标准,硬盘分区表的结构含义