从火箭发场景来学习Java多线程并发闭锁对象

倒计时器场景

在我们开发过程中,有时候会使用到倒计时计数器。最简单的是:int size = 5; 执行后,size—这种方式来实现。但是在多线程并发的情况下,这种操作会不安全的。举个现实中最典型的一个例子:火箭发射的案例。

大家都看过火箭发射的直播吧。火箭在发送的时候,有很多设备需要检查是否都准备就绪。在总控室得到所有设备都准备就绪后,才会下达发射的命令。我们也知道,火箭发射有很多设备需要检验,这不是一个部门一个一个检查的,而是多个部门协同配合实现的。如果把一个个部门看作不同的线程的话。我们就可以假设:

如果是一个部门一个一个设备检查,这就是单线程操作的;

如果是多个部门协同配合的话,就是多线程的。

所以说,在火箭发射前检查设备是 多线程情况下进行的。

我们也不知道,不同部门负责检查的设备的复杂度不同,速度不同,就会导致有些部门检查完成的快,有些部门检查完成的慢。这个过程我们可以理解为不同线程在竞争CPU资源的时候不同。

假设有5个部门同时协同工作,这5个部门的操作可以看作是一组操作。因为速度不同,那么总控室下达发射的命令是以哪个检查完毕为准呢?是A部门还是B部门或者D部门呢?都不是,总控室下达发射的命令是在得到5个部门都检查完毕后才会下达发射的命令。我们也可以理解为总控室在得到这一组(五个部门)都操作完成才执行的。此时总控室可以理解为一个线程,五个部门一组可以理解一个线程组。

从上面现实生活中的案例分析,我们来想想上面的操作用Java程序怎么实现 ?

使用count—的代码实现

模拟不同部门的线程:

我们先来看看常规的。使用count--的效果。

模拟总控室的主线程:

从上面代码中,我们可以看到当计数器count减到0的时候,总控室下达发射命令。这个从逻辑上来说,是正确的,没问题的。我们来看看运行结果:

运行结果:

从运行结果,我们可以看到,当总控室接收到count =0的指令后,认为各个部门都已经检查完毕了。所以就下达了发射命令。但是在最后,我们发现火箭已经发射了,部门4和5才向总控室汇报检查完毕,准备就绪。这种情况是很危险的。因为我们知道火箭的造价是很昂贵的而且凝聚了很多科研人员的心血。如果因为某个部门未检查完毕就发射而导致火箭发射失败或者坠落,在现实生活中,这种情况是不允许出现的。

那么这种情况,在Java中,怎么解决呢?可以使用countdownlatch这个对象来解决。

Countdownlatch

Countdownlatch是什么?

先来看看源码中怎么解释的:A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

什么意思呢?

简单的来说,是一个同步辅助工具类,运行一个或多个线程在等待其他线程完成一组操作后再接着执行的工具类。

实现的流程:

通过一个计数器来实现的,计数器的初始值就是要执行的线程的数量。每当一个线程执行完毕之后,计数器的值就会减一,当计数器的值减少到0的时候,表示所有的线程都执行完毕了。然后再闭锁上等待的其他线程就可以恢复正常工作了。

来看看主要的方法

说明:

Sync:是countdownlatch内部类,继承AbstractQueuedSynchronizer使用AQS状态来代替计数的。

有参构造器:public CountDownLatch(int count){}

await():等待方法。还有一个带参数重载的方法。

countdown():执行计数器减1操作的方法。

使用countdownlatch模拟火箭发射前准备代码:

我们来看看使用countdownlatch来模拟火箭发射前准备会不会出问题。

来看看模拟部门的线程代码:

为了保证计数器减一操作不受子线程运行结果影响,讲count.coundDown()操作放在finally代码块里面。

再来看看总控室下达发射命令的主线程:

在downLatch.await()之后,下达发射命令。

查看运行结果:

我们可以看到,当所有部门都准备就绪后,总控室接收到完成的指令后,下达发射火箭命令。这个流程才是正常的。从运行结果来看也是正常的。

使用场景:

场景1:某线程在运行前需要等待其他N个线程执行完成之后在执行。

比如:

容器启动spring 容器的启动,需要初始化、bean装配、检查其他依赖等加载完毕之后,在主线程在继续执行;

在比如:电商中统计库存问题。我们知道,一个电商项目有很多分类,不同分类下的库存不一样。如果要统计当前剩余总库存。这个时候,就可以使用其他线程统计每个分类下的库存。等所有分类都统计完成之后,主线程在进行汇总操作。

关注凯哥:

个人博客:www.kaigejava.com

个人公众号:凯哥Java(kaigejava)

从火箭发场景来学习Java多线程并发闭锁对象的更多相关文章

  1. Java 多线程并发编程一览笔录

    Java 多线程并发编程一览笔录 知识体系图: 1.线程是什么? 线程是进程中独立运行的子任务. 2.创建线程的方式 方式一:将类声明为 Thread 的子类.该子类应重写 Thread 类的 run ...

  2. Java多线程并发05——那么多的锁你都了解了吗

    在多线程或高并发情境中,经常会为了保证数据一致性,而引入锁机制,本文将为各位带来有关锁的基本概念讲解.关注我的公众号「Java面典」了解更多 Java 相关知识点. 根据锁的各种特性,可将锁分为以下几 ...

  3. Java多线程并发工具类-信号量Semaphore对象讲解

    Java多线程并发工具类-Semaphore对象讲解 通过前面的学习,我们已经知道了Java多线程并发场景中使用比较多的两个工具类:做加法的CycliBarrier对象以及做减法的CountDownL ...

  4. Java多线程并发02——线程的生命周期与常用方法,你都掌握了吗

    在上一章,为大家介绍了线程的一些基础知识,线程的创建与终止.本期将为各位带来线程的生命周期与常用方法.关注我的公众号「Java面典」了解更多 Java 相关知识点. 线程生命周期 一个线程不是被创建了 ...

  5. Java多线程并发07——锁在Java中的实现

    上一篇文章中,我们已经介绍过了各种锁,让各位对锁有了一定的了解.接下来将为各位介绍锁在Java中的实现.关注我的公众号「Java面典」了解更多 Java 相关知识点. 在 Java 中主要通过使用sy ...

  6. Java多线程并发08——锁在Java中的应用

    前两篇文章中,为各位带来了,锁的类型及锁在Java中的实现.接下来本文将为各位带来锁在Java中的应用相关知识.关注我的公众号「Java面典」了解更多 Java 相关知识点. 锁在Java中主要应用还 ...

  7. Java多线程-并发容器

    Java多线程-并发容器 在Java1.5之后,通过几个并发容器类来改进同步容器类,同步容器类是通过将容器的状态串行访问,从而实现它们的线程安全的,这样做会消弱了并发性,当多个线程并发的竞争容器锁的时 ...

  8. Java多线程并发技术

    Java多线程并发技术 参考文献: http://blog.csdn.net/aboy123/article/details/38307539 http://blog.csdn.net/ghsau/a ...

  9. java 多线程并发问题总结

    java 多线程并发主要通过关键字synchronized实现 Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并发线程访问 ...

随机推荐

  1. [LC] 226. Invert Binary Tree

    Invert a binary tree. Example: Input: 4 / \ 2 7 / \ / \ 1 3 6 9 Output: 4 / \ 7 2 / \ / \ 9 6 3 1 /* ...

  2. Python sorted函数详解(高级篇)

    sorted() 函数对所有可迭代的对象进行排序操作. sort 与 sorted 区别: sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作. list 的 s ...

  3. 设置Fiddler来抓取Android接口数据

    1.下载安装fiddler,安装包可自行百度.安装完成打开fiddler 2.将Fiddler设置远程访问PC 选择Fiddler->Tools->Fiddler Option 3.选择C ...

  4. Hell World:)

    第一次弄博客是在2017年春节,自己弄了个域名,租了个小小的VPS,装好了wordpress,挑了一套模板,就这样上线了,可惜wordpress实在不是一个适合写字的地方,插件.主题令人眼花缭乱,慢慢 ...

  5. iOS(Swift)学习笔记之SnapKit+自定义UI组件

    本文为原创文章,转载请标明出处 1. 通过CocoaPods安装SnapKit platform :ios, '10.0' target '<Your Target Name>' do u ...

  6. cesium入门示例-3dTiles加载

    数据转换工具采用cesiumlab1.5.17版本,转换后的3dTiles加载显示比较简单,通过Cesium.Cesium3DTileset接口指定url即可,3dTiles文件可与js前端代码放置一 ...

  7. [洛谷P4549] [模板] 裴蜀定理

    18.10.03模拟赛T1. 出题人xcj(Mr.Handsome)十分良心,给了一道送分题...... 互测题好久没有出现送分题了.xcj真棒. 题目传送门 幸亏之前看过,否则真的是送分题都拿不到. ...

  8. 二、Android XML数据解析

    XML,可扩展标记语言.可以用来存储数据,可以看做是一个小型的数据库,SharedPreference就是使用XML文件存储数据的,SQLite底层也是一个XML文件,而在网络应用方面,通常作为信息的 ...

  9. 配置Maven本地仓库

    以本机为例: 系统:Windows 开发工具:IDEA 如果想在dos窗口输mvn命令,需配置环境变量. 1. 在D盘新建repository文件夹,该目录用作maven的本地库. 2. 打开D:\P ...

  10. Fragment argument

    每个Fragment实例都可以附带一个Bundle对象,该bundle包含键值对,可以像附加extra到Activity的intent中那样使用他们.一个键值对即一个argument. 创建frage ...