Java多线程-两种常用的线程计数器CountDownLatch和循环屏障CyclicBarrier
Java多线程编程-(1)-线程安全和锁Synchronized概念
Java多线程编程-(2)-可重入锁以及Synchronized的其他基本特性
Java多线程编程-(3)-从一个错误的双重校验锁代码谈一下volatile关键字
Java多线程编程-(4)-线程本地ThreadLocal的介绍与使用
Java多线程编程-(6)-你还在使用wait/notify实现进程间的通信吗?
Java多线程编程-(7)-使用ReentrantReadWriteLock实现Lock并发
一、倒计时CountDownLatch
CountDownLatch是一个非常实用的多线程控制工具类,称之为“倒计时器”,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行。
举了例子:
我们知道的集齐七颗龙珠就可以召唤神龙,那我们就一起召唤一下,下边我需要派7个人(7个线程)去分别去找这7颗不同的龙珠,每个人找到之后回来告诉我还需要等待的龙珠个数减1个,那么当全部的人都找到龙珠之后,那么我就可以召唤神龙了。
顺便写个代码如下:
运行结果如下:
上述的执行结果可以看出,当分配的7个人(7个线程)分别找到龙珠之后,也就是所有的线程执行完毕,才可以召唤龙珠(执行countDownLatch.await()之后的代码)。
注意:
(1)CountDownLatch的构造函数
7表示需要等待执行完毕的线程数量。
(2)在每一个线程执行完毕之后,都需要执行countDownLatch.countDown()
方法,不然计数器就不会准确;
(3)只有所有的线程执行完毕之后,才会执行 countDownLatch.await()
之后的代码;
(4)可以看出上述代码中CountDownLatch 阻塞的是主线程;
那么,假如我们不是用计数器CountDownLatch的话,结果可想而知,示例如下:
结果只能呵呵了!
好啦!上边说了一堆水话,下面说点官方的解释:
CountDownLatch是在java1.5被引入的,它存在于java.util.concurrent包下。CountDownLatch这个类能够使一个线程等待其他线程完成各自的工作后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有的框架服务之后再执行。
CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。
CountDownLatch.java类中定义的构造函数:
构造器中的计数值(count)实际上就是闭锁需要等待的线程数量。这个值只能被设置一次,而且CountDownLatch没有提供任何机制去重新设置这个计数值。
与CountDownLatch的第一次交互是主线程等待其他线程。主线程必须在启动其他线程后立即调用CountDownLatch.await()方法。这样主线程的操作就会在这个方法上阻塞,直到其他线程完成各自的任务。
其他N 个线程必须引用闭锁对象,因为他们需要通知CountDownLatch对象,他们已经完成了各自的任务。这种通知机制是通过 CountDownLatch.countDown()方法来完成的;每调用一次这个方法,在构造函数中初始化的count值就减1。所以当N个线程都调用了这个方法,count的值等于0,然后主线程就能通过await()方法,恢复执行自己的任务。
二、CountDownLatch在实时系统中的使用场景
让我们尝试罗列出在java实时系统中CountDownLatch都有哪些使用场景。我所罗列的都是我所能想到的。如果你有别的可能的使用方法,请在留言里列出来,这样会帮助到大家。
(1)实现最大的并行性:有时我们想同时启动多个线程,实现最大程度的并行性。例如,我们想测试一个单例类。如果我们创建一个初始计数为1的CountDownLatch,并让所有线程都在这个锁上等待,那么我们可以很轻松地完成测试。我们只需调用 一次countDown()方法就可以让所有的等待线程同时恢复执行。
(2)开始执行前等待n个线程完成各自任务:例如应用程序启动类要确保在处理用户请求前,所有N个外部系统已经启动和运行了。
(3)死锁检测:一个非常方便的使用场景是,你可以使用n个线程访问共享资源,在每次测试阶段的线程数目是不同的,并尝试产生死锁。
三、循环屏障CyclicBarrier
CyclicBarrier是另一种多线程并发控制使用工具,和CountDownLatch非常类似,他也可以实现线程间的计数等待,但他的功能要比CountDownLatch更加强大一些。
CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。
CyclicBarrier默认的构造方法是CyclicBarrier(int parties)
,其参数表示屏障拦截的线程数量,每个线程调用await
方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。
CyclicBarrier强调的是n个线程,大家相互等待,只要有一个没完成,所有人都得等着。
还接着上述“集齐七颗龙珠!召唤神龙”的故事。召唤神龙,需要7个法师去寻找龙珠,但这7个法师并不是一下子就能号召起来的,所以要等待召集齐7个法师,然后在秋名山顶烧香拜佛为这7位法师送行,让他们同时出发,前往不同的地方寻找龙珠(敲黑板:这是第一个屏障点),在这七位法师临行时约定找到龙珠之后还回到这个地方等待其他法师找到龙珠之后一起去见我。几年之后,第一个法师回来了,然后等待其他的法师。。。,最后所有的法师全部到齐(敲黑板:这是第一个屏障点),然后组队来找我召唤神龙。
示例代码如下:
执行结果:
代码中设置了两个屏障点,第一个用于召集7个法师,等7个法师召集完后,在设置在一个屏障点,7位法师去寻找龙珠,然后召唤神龙,中间有个嵌套的关系!
上述的例子,大致说了一下屏障,因为设置了两个屏障,并没有演示上述说的可循环使用(Cyclic)的屏障(Barrier) 中的可循环使用(Cyclic)
查看CyclicBarrier.reset()
可知,可以使CyclicBarrier回到最初始的状态,由于使用的相对较少,这里不再演示。
四、CyclicBarrier和CountDownLatch的区别
(1)CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可以使用reset() 方法重置。所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次。
(2)CyclicBarrier还提供其他有用的方法,比如getNumberWaiting方法可以获得CyclicBarrier阻塞的线程数量。isBroken方法用来知道阻塞的线程是否被中断。比如以下代码执行完之后会返回true。
(3)CountDownLatch会阻塞主线程,CyclicBarrier不会阻塞主线程,只会阻塞子线程。
Java多线程-两种常用的线程计数器CountDownLatch和循环屏障CyclicBarrier的更多相关文章
- Java多线程--两种实现方式
进程概述: 在这之前,有必要了解一下什么是进程? 在一个操作系统中,每个独立的执行的程序都可称为一个进程,也就是"正在运行的程序".如图所示: 线程概述: 如上所述,每个运行的程序 ...
- java多线程 —— 两种实际应用场景模拟
最近做的偏向并发了,因为以后消息会众多,所以,jms等多个线程操作数据的时候,对共享变量,这些要很注意,以防止发生线程不安全的情况. (一) 先说说第一个,模拟对信息的发送和接收.场景是这样的: 就像 ...
- JAVA - 多线程 两种方法的比较
一.继承Thread类 实现方法: (1).首先定义一个类去继承Thread父类,重写父类中的run()方法.在run()方法中加入具体的任务代码或处理逻辑.(2).直接创建一个ThreadDemo2 ...
- Java中两种实现多线程方式的对比分析
本文转载自:http://www.linuxidc.com/Linux/2013-12/93690.htm#0-tsina-1-14812-397232819ff9a47a7b7e80a40613cf ...
- Java中有两种实现多线程的方式以及两种方式之间的区别
看到一个面试题.问两种实现多线程的方法.没事去网上找了找答案. 网上流传很广的是一个网上售票系统讲解.转发过来.已经不知道原文到底是出自哪里了. Java中有两种实现多线程的方式.一是直接继承Thre ...
- java 中几种常用数据结构
Java中有几种常用的数据结构,主要分为Collection和map两个主要接口(接口只提供方法,并不提供实现),而程序中最终使用的数据结构是继承自这些接口的数据结构类. 一.几个常用类的区别 1.A ...
- Java多线程学习(八)线程池与Executor 框架
目录 历史优质文章推荐: 目录: 一 使用线程池的好处 二 Executor 框架 2.1 简介 2.2 Executor 框架结构(主要由三大部分组成) 2.3 Executor 框架的使用示意图 ...
- Java 多线程基础(四)线程安全
Java 多线程基础(四)线程安全 在多线程环境下,如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线 ...
- Java 多线程基础(十一)线程优先级和守护线程
Java 多线程基础(十一)线程优先级和守护线程 一.线程优先级 Java 提供了一个线程调度器来监控程序启动后进去就绪状态的所有线程.线程调度器通过线程的优先级来决定调度哪些线程执行.一般来说,Ja ...
随机推荐
- Linux里提示cannot find -lsocket解决办法
今天在我的Linux make时提示我找不到 -lsocket,我就去lib库里查了一下,根本没有这个东东,然后在网上看了好多都是说缺少这个库要安装,或是要改libsock.so,试了半天都没有用. ...
- Android——修改Button样式,动态修改Button中的图片大小
原文地址: http://www.cnblogs.com/gzggyy/archive/2013/05/17/3083218.html http://www.xuebuyuan.com/2173740 ...
- VBA中数据库导出数据到Excel注意事项
Sub ReadDBData() On Error GoTo ErrorHand Dim dbHelper As New dbHelper Dim sqlSQL As String Dim rs As ...
- Spark部署
Spark的部署让人有点儿困惑,有些需要注意的事项,本来我已经装成功了YARN模式的,但是发现了一些问题,出现错误看日志信息,完全看不懂那个错误信息,所以才打算翻译Standalone的部署的文章.第 ...
- sql server 2012 删除服务器名称
SQL Server 2008 R2及以前版本: http://blog.csdn.net/downmoon/article/details/5678468 SQL Server 2012: 删除这两 ...
- centos7安装rabbitmq3.7
centos7安装rabbitmq3.7安装erlang # vim /etc/yum.repos.d/rabbitmq-erlang.repo [rabbitmq-erlang] name=rabb ...
- C#内置泛型委托:Func委托
1.什么是Func委托 Func委托代表有返回类型的委托 2.Func委托定义 查看Func的定义: using System.Runtime.CompilerServices; namespace ...
- org.apache.catalina.LifecycleException异常的处理
今天调试了很久,重装tomcat都没用,后来发现是xml servlet的url-pattern的配置少写一个"/",添加后启动即可. org.apache.catalina.Li ...
- R语言 data.frame 大全
A data frame is used for storing data tables. It is a list of vectors of equal length. For example, ...
- VMWare Workstation虚拟机网卡工作模式及配置方法
打开VMware→虚拟机→设置.如下图 一. 桥接模式(Bridge) 可将虚拟系统IP与本地系统设在同一网段,此时虚拟机相当于一台网络中与本机公用一个HUB的独立设备,网络中其他机器与虚拟机器.本地 ...