Java并发之同步工具类
1. CountDownlatch(计数器)
描述:
一个同步工具类,允许一个或多个线程等待其它线程完成操作
类图

通过指定的count值进行初始化,调用await方法的线程将被阻塞,直到count值通过countDown()方法减小到0,所有等待的线程才会被释放继续执行。另外CountDownLatch不可能重新初始化或者修改CountDownLatch对象的内部计数器的值
事例:
package com.lkf.concurrent;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import static java.util.concurrent.Executors.newFixedThreadPool;
public class CountDownlatchTest {
/**
* 计数器,用来控制线程数量,传入参数2,表示计数器计数为2
*/
private final static CountDownLatch M_COUNT_DOWN_LATCH = new CountDownLatch(2);
/**
* 示例工作线程类
*/
private static class WorkerThreadA implements Runnable {
private final String mThreadName;
private final int mSleepTime;
public WorkerThreadA(String name, int sleepTime) {
mThreadName = name;
mSleepTime = sleepTime;
}
@Override
public void run() {
System.out.println("[" + mThreadName + "] started!");
try {
Thread.sleep(mSleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
M_COUNT_DOWN_LATCH.countDown();
System.out.println("[" + mThreadName + "] end!");
}
}
/**
* 工作线程类
*/
private static class WorkerThreadB implements Runnable {
@Override
public void run() {
System.out.println("[WorkerThread] started!");
try {
// 阻塞在这里等待 mCountDownLatch 里的count变为0;
M_COUNT_DOWN_LATCH.await();
} catch (InterruptedException e) {
}
System.out.println("[WorkerThread] end!");
}
}
public static void main(String[] args) throws Exception {
ExecutorService executorService = newFixedThreadPool(3);
// 最先run WorkerThread
executorService.submit(new WorkerThreadB());
// 运行两个工作线程
// 工作线程1运行3秒
executorService.submit(new WorkerThreadA("WorkingThread1", 3000));
// 工作线程2运行2秒
executorService.submit(new WorkerThreadA("WorkingThread2", 2000));
}
}
2. CyclicBarrier(同步屏障)
描述
CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。CyclicBarrier默认的构造方法是CyclicBarrier(intparties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞
类图

事例
package com.lkf.concurrent;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierTest {
public static void main(String[] args) {
//初始化四个线程
int threadNum = 4;
CyclicBarrier barrier = new CyclicBarrier(threadNum, new WorkerThreadA());
for (int i = 0; i < threadNum; i++) {
new WorkerThread(barrier).start();
}
}
static class WorkerThread extends Thread {
private CyclicBarrier cyclicBarrier;
public WorkerThread(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
System.out.println("线程" + Thread.currentThread().getName() + "正在执行");
try {
Thread.sleep(5000); //以睡眠来模拟操作
System.out.println("线程" + Thread.currentThread().getName() + "执行完毕,等待其他线程执行完成");
cyclicBarrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("所有线程执行完成,继续处理其他任务...");
}
}
static class WorkerThreadA extends Thread {
@Override
public void run() {
System.err.println("我是特殊任务");
}
}
}
有一个高级构造函数,当一组线程执行完毕后,优先执行某个方法,CyclicBarrier(int parties, Runnable barrierAction),可以用来处理特殊的任务
应用场景
CyclicBarrier可以用于多线程计算数据,最后合并计算结果的应用场景。比如一个1000万行数据的大文件,统计数据最大的钱五个数,假如我们用五个线程,将大文件分成5份,分别计算每一份中最大的数,最后,barrierAction用这些线程的计算结果,计算出整个文件中最大的五个数。
CyclicBarrier和CountDownLatch的区别
CountDownLatch的计数器只能使用一次,CyclicBarrier的计数器可以使用reset() 方法重置。所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次。
CyclicBarrier还提供其他有用的方法,比如getNumberWaiting方法可以获得CyclicBarrier阻塞的线程数量。isBroken方法用来知道阻塞的线程是否被中断。比如以下代码执行完之后会返回true。
3. Semaphore(信号量)
描述
Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源,就是控制并发线程的数量
类图

应用场景
Semaphore可以用于做流量控制,特别公用资源有限的应用场景,比如数据库连接。假如有一个需求,要读取几万个文件的数据,因为都是IO密集型任务,我们可以启动几十个线程并发的读取,但是如果读到内存后,还需要存储到数据库中,而数据库的连接数只有10个,这时我们必须控制只有十个线程同时获取数据库连接保存数据,否则会报错无法获取数据库连接。这个时候,我们就可以使用Semaphore来做流控
事例
public class SemaphoreTest {
private static final int THREAD_COUNT = 30;
private static ExecutorService threadPool = newFixedThreadPool(THREAD_COUNT);
private static Semaphore s = new Semaphore(10);
public static void main(String[] args) {
for (int i = 0; i < THREAD_COUNT; i++) {
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
s.acquire();
System.out.println("save data");
s.release();
} catch (InterruptedException e) {
}
}
});
}
threadPool.shutdown();
}
}
其他方法
Semaphore还提供一些其他方法:
int availablePermits() :返回此信号量中当前可用的许可证数。
int getQueueLength():返回正在等待获取许可证的线程数。
boolean hasQueuedThreads() :是否有线程正在等待获取许可证。
void reducePermits(int reduction) :减少reduction个许可证。是个protected方法。
Collection getQueuedThreads() :返回所有等待获取许可证的线程集合。是个protected方法。
4. Exchanger(线程间数据交换)
描述
Exchanger(交换器)是一个用于线程间协作的工具类。Exchanger用于进行线程间的数据交换。它提供一个同步点,在这个同步点两个线程可以交换彼此的数据。这两个线程通过exchange方法交换数据, 如果第一个线程先执行exchange方法,它会一直等待第二个线程也执行exchange,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方
类图

应用场景
Exchanger可以用于遗传算法,遗传算法里需要选出两个人作为交配对象,这时候会交换两人的数据,并使用交叉规则得出2个交配结果。
Exchanger也可以用于校对工作。比如我们需要将纸制银流通过人工的方式录入成电子银行流水,为了避免错误,采用AB岗两人进行录入,录入到Excel之后,系统需要加载这两个Excel,并对这两个Excel数据进行校对,看看是否录入的一致
事例
public class ExchangerTest {
//交换器
private static final Exchanger<String> exgr = new Exchanger<String>();
//线程池
private static ExecutorService threadPool = newFixedThreadPool(2);
public static void main(String[] args) {
threadPool.execute(() -> {
try {
String threadAData = "线程A的数据";
exgr.exchange(threadAData);
} catch (InterruptedException e) {
}
});
threadPool.execute(() -> {
try {
String threadBData = "线程B的数据";
String threadAData = exgr.exchange("B");
System.out.println("A和B数据是否一致:" + threadAData.equals(threadBData) + ",A录入的是:"
+ threadAData + ",B录入是:" + threadBData);
} catch (InterruptedException e) {
}
});
threadPool.shutdown();
}
}
其它方法
如果两个线程有一个没有到达exchange方法,则会一直等待,如果担心有特殊情况发生,避免一直等待,可以设置最大等待时长。
public V exchange(V x, long timeout, TimeUnit unit)
Java并发之同步工具类的更多相关文章
- Java并发之CyclicBarrier工具类
一.CyclicBarrier工具类介绍 在上一篇文中我们介绍到了CountDownLatch工具类,其实CyclicBarrier和CountDownLatch工具类实现的功能差不多.我们可以从字面 ...
- Java并发之CountDownLatch工具类
一.CountDownLatch工具类介绍 CountDownLatch类是Java并发工具常用的四大工具之一,CountDownLatch允许一个或者多个线程等待其他线程完成工作.假设我们有这样的一 ...
- Java核心知识点学习----线程同步工具类,CyclicBarrier学习
线程同步工具类,CyclicBarrier日常开发较少涉及,这里只举一个例子,以做备注.N个人一块出去玩,相约去两个地方,CyclicBarrier的主要作用是等待所有人都汇合了,才往下一站出发. 1 ...
- 《java并发编程实战》读书笔记4--基础构建模块,java中的同步容器类&并发容器类&同步工具类,消费者模式
上一章说道委托是创建线程安全类的一个最有效策略,只需让现有的线程安全的类管理所有的状态即可.那么这章便说的是怎么利用java平台类库的并发基础构建模块呢? 5.1 同步容器类 包括Vector和Has ...
- java 利用同步工具类控制线程
前言 参考来源:<java并发编程实战> 同步工具类:根据工具类的自身状态来协调线程的控制流.通过同步工具类,来协调线程之间的行为. 可见性:在多线程环境下,当某个属性被其他线程修改后,其 ...
- Java多线程同步工具类之CountDownLatch
在过去我们实现多线程同步的代码中,往往使用join().wait().notiyAll()等线程间通信的方式,随着JUC包的不断的完善,java为我们提供了丰富同步工具类,官方也鼓励我们使用工具类来实 ...
- Java并发(基础知识)——显示锁和同步工具类
显示锁 Lock接口是Java ...
- java.util.concurrent中的几种同步工具类
java.util.concurrent并发包中提供了一系列的的同步工具类,这些基础类不管是否能在项目中使用到,了解一下使用方法和原理对java程序员来说都是有必要的.博主在看<java并发编程 ...
- 并发是个什么鬼之同步工具类CountDownLatch
扯淡 写这篇文章,我先酝酿一下,实不相瞒,脱离底层太久了,更确切的情况是,真没曾认真研究过.就目前来说,很多框架包括工具类已经把实现封装的很深,你只需轻轻的调用一下API,便不费半点力气.以至于大家会 ...
随机推荐
- 数据库(mysql和oracle)
1. mysql索引: https://www.jikewenku.com/22030.html 2.
- MyEclipse10.0 采用插件方式安装 SVN
一.到官方上下载svn1.8.3,下载后的文件名叫site-1.8.3.zip 地址:http://subclipse.tigris.org/servlets/ProjectDocumentList? ...
- spark2.0新特性之DataSet
1.Spark SQL,DataFrame,DataSet的错误类型检测时机 spark SQL:其类型检测与语法检测是在运行时检测的 DataFrame:在spark2.0以前的版本中,DataFr ...
- Oracle 调试存储过程
调试过程对找到一个存过的bug或错误是非常重要的,Oracle作为一款强大的商业数据库,其上面的存过少则10几行,多则上千行,免不了bug的存在,存过上千行的话,找bug也很费力,通过调试可以大大减轻 ...
- Objective-C 之Extension
Objective-C 之Extension class extension:类扩展 类扩展与 category 有相似性,但在编译时它只能被添加到已有源代码的一类中(该类扩展和该类同时被编译). 在 ...
- STM32启动BOOT0 BOOT1设置方法
原理图 启动方式 第一种启动方式是最常用的用户FLASH启动.默认启动方式 第二种启动方式是STM32内嵌的SRAM启动.该模式用于调试 第三种启动方式是系统存储器启动方式,不建议使用这种,速度比较慢 ...
- 如何使用Marketing Cloud的扩展字段作为搜索条件进行搜索
需求:我在Marketing Cloud的contact模型上用custom field这个应用创建了一个Extension field,名称为微信ID. 现在客户的需求是使用这个字段作为过滤条件进行 ...
- 【uoj#46】 [清华集训2014] 玄学
题目传送门:uoj46 题意简述:要求在序列上维护一个操作间支持结合律的区间操作,查询连续一段时间内的操作对单点的作用效果,\(n \leq 10^5,m \leq 6 \times 10^5 ...
- 05_Hive分区总结
2.1.创建分区表并将本地文件的数据加载到分区表: 使用下面的命令来创建一个带分区的表 通过partitioned by(country string)关键字声明该表是分区表,且分区字段不能为crea ...
- Caffe---Pycaffe进行网络结构(xxx.prototxt)可视化
Pycaffe---进行网络结构(xxx.prototxt)可视化 解决网络结构(xxx.prototxt)可视化,还可以借助python接口,编写一个类似如下的pycaffe_draw_net.py ...