J.U.C 系列之 Tools
JDK 5.0 开始,java并发大师Doug lea 为我们带来了更高效更应用的java并发API Java.util.concurrent包,简称J.U.C
J.U.C 体系由如下五个知识结构构成
本节我们首先来介绍其中的并发辅助工具类 Tools
Tools又由几个主要的工具类构成,如下所示‘
一 等待多线程完成的CountDownLatch
CountDownLatch允许一个或者多个线程等待其他线程完成操作。
假如有这样一个需求:我们需要解析一个Excel表里面的多个sheet数据,此时可以考虑使用多线程,每个线程解析一个sheet里的数据,等到多有sheet的数据都解析完成之后,程序需要提示解析完成。在这个需求里面要求实现主线程等待所有线程完成sheet的解析操作,最简单的就是使用Thread 的join方法,这里不在讨论,若不清楚可以自行查看,我们这里来看看若使用CountDownLatch如何实现。
代码如下若是
import java.util.concurrent.CountDownLatch;
public class CountDownLatchTest {
/*
* CountDownLatch 构造函数接受一个int 类型的参数作为计数器。如果你想等待N个点完成,
这里就传入N.这里我们测试等待2个点完成
每次调用countDown方法N就会减一
*/
static CountDownLatch c = new CountDownLatch(2);
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(1);
c.countDown();
System.out.println(2);
c.countDown();
}
}).start();
//await 方法会阻塞当前线程,直到计数器N的值变为0,
//由于countDown方法可以在任何线程执行,所以这里的N个点可以是N个线程
c.await();
System.out.println(3);
}
}
如果某个sheet的解析处理的异常缓慢,我们不可能让主线程一直等待,所以可以使用另一个带超时等待的await方法await(Long time,TimeUnit unit),这个方法等待指定时间后,就不会继续阻塞当前线程。
注:countDownLatch不能够重新初始化或者修改内部计数器值
二 同步循环屏障 CyclicBarrier
CyclicBarrier的字面量的意思是可循环使用的屏障。它主要做的是,让一组线程达到一个屏障时被阻塞,直到最后一个线程到达屏障点时,屏障才会被打开,所有被屏障拦截的线程才会继续执行。
具体效果图如下所示
CyclicBarrier 提供2个构造方法:
public CyclicBarrier(int parties, Runnable barrierAction) {
}
public CyclicBarrier(int parties) {
}
参数parties指让多少个线程或者任务等待至barrier状态;参数barrierAction为当这些线程都达到barrier状态时首先执行的任务。
下面我们通过实例演示如何使用CyclicBarrier
package com.wirt; import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier; public class CyclicBarrierTest { static CyclicBarrier c = new CyclicBarrier(2,new A()); public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
try {
c.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(1); }
}).start(); try {
c.await();
} catch (BrokenBarrierException e) {
e.printStackTrace();
} System.out.println(2);
} static class A implements Runnable{ @Override
public void run() {
System.out.println(3);
} }
}
因为设置了拦截数量是2,且两个线程都到达屏障后优先执行A任务,然后在执行到达屏障的任务
三 控制并发线程数的Semaphore
Semaphore(信号量)是用来控制同时访问特定资源的线程数量,他通过协调各个线程以保证合理的使用公共资源。
Semaphore 可以用于做流量控制,特别是公共资源的应用场景,比如数据库连接,加入有一个需求,要读取几万个文件的数据,因为都是IO密集型任务,我们可以启动几十个线程并发的读取。但是到读到内存后,还是要存储到数据库中,而数据库的连接数只有十个,这是我们必须控制只有十个线程同时获取数据库连接保存数据,否则报错无法获取数据库连接,这个时候,就可以使用Semaphore来做流量控制。示例代码如下
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore; public class SemaphoreTest { private static final int COUNT = 30; private static ExecutorService threadPool = Executors.newFixedThreadPool(COUNT); private static Semaphore s = new Semaphore(10); public static void main(String[] args) {
for(int i =0;i<COUNT;i++){
threadPool.execute(new Runnable() { @Override
public void run() {
try {
s.acquire(); //获取许可证
System.out.println("save data");
s.release(); //释放许可证
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
} threadPool.shutdown();
}
}
在代码中,虽然有30个线程任务在执行,但是只有10个线程可以同时并发执行。
四 线程间交换数据的Exchanger
Exchanger 是一个用于线程间协作的工具类,用于进行线程间的数据交换,它提供一个同步点,在这个同步点,两个线程通过执行exchanger方法,进行交换数据,如果第一个线程先执行exchanger,它会阻塞等待第二个线程执行exchanger方法,当两个线程都达到同步点时,这两个线程交换数据。
下面通过示例演示Exchanger用法
package com.wirt; import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore; public class ExchangerTest {
private static final Exchanger<String> exgr = new Exchanger<String>(); private static final ExecutorService threadPool = Executors.newFixedThreadPool(2); public static void main(String[] args) {
threadPool.execute(new Runnable() { @Override
public void run() {
String A = "银行流水A"; //A录入银行流水数据
try {
exgr.exchange(A);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}); threadPool.execute(new Runnable() { @Override
public void run() {
String B = "银行流水B"; //B录入银行流水数据
try {
String A = exgr.exchange(B);
System.out.println("A和B数据是否一致:"+A.equals(B)+"; A="+A+"; B="+B);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}); threadPool.shutdown();
}
}
五 总结
| 工具类 | 使用场景 |
| CountDownLatch | 多线程同时解析一个Excel中多个sheet,等到所有sheet解析完成,程序提示完成 |
| CyclicBarrier | 多线程计算数据,最后合并计算结果 |
| Semaphore | 用于流量控制,特别是公共资源有限情况下的应用场景,例如数据库连接 |
| Exchanger | 1 可以用于遗传算法 2 可以用于校对工作 |
参考:《Java并发编程艺术》
工具类之Executors放在下一节
J.U.C 系列之 Tools的更多相关文章
- J.U.C 系列 Tools之Executors
上个章节说了Tools中的其他四个工具类,本节我们来看一看工具类中的老大Executors,为什么说它是老大,肯定是因为他的功能最多最强大. 一 Executors是什么 Executors 是一个线 ...
- j.u.c系列(11)---之并发工具类:Exchanger
写在前面 前面三篇博客分别介绍了CyclicBarrier.CountDownLatch.Semaphore,现在介绍并发工具类中的最后一个Exchange.Exchange是最简单的也是最复杂的,简 ...
- j.u.c系列(06)---之锁条件:Condition
写在前面 在没有Lock之前,我们使用synchronized来控制同步,配合Object的wait().notify()系列方法可以实现等待/通知模式.在Java SE5后,Java提供了Lock接 ...
- j.u.c系列(03)---之AQS:AQS简介
写在前面 Java的内置锁一直都是备受争议的,在JDK 1.6之前,synchronized这个重量级锁其性能一直都是较为低下,虽然在1.6后,进行大量的锁优化策略,但是与Lock相比synchron ...
- Day9 - J - 吉哥系列故事——恨7不成妻 HDU - 4507
单身! 依然单身! 吉哥依然单身! DS级码农吉哥依然单身! 所以,他生平最恨情人节,不管是214还是77,他都讨厌! 吉哥观察了214和77这两个数,发现: 2+1+4=7 7+7=7*2 77=7 ...
- j.u.c系列(10)---之并发工具类:Semaphore
写在前面 Semaphore是一个计数信号量,它的本质是一个"共享锁". 信号量维护了一个信号量许可集.线程可以通过调用acquire()来获取信号量的许可:当信号量中有可用的许可 ...
- j.u.c系列(09)---之并发工具类:CyclicBarrier
写在前面 CyclicBarrier是一个同步辅助类,允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point).因为该 barrier 在释放等待线程后可以重用,所以 ...
- j.u.c系列(08)---之并发工具类:CountDownLatch
写在前面 CountDownLatch所描述的是”在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待“:用给定的计数 初始化 CountDownLatch.由于调用了 countDo ...
- j.u.c系列(07)---之读写锁:ReentrantReadWriteLock
写在前面 重入锁ReentrantLock是排他锁,排他锁在同一时刻仅有一个线程可以进行访问,但是在大多数场景下,大部分时间都是提供读服务,而写服务占有的时间较少.然而读服务不存在数据竞争问题,如果一 ...
随机推荐
- 17.NET Core WebApi跨域问题
官方说明 CORS means Cross-Origin Resource Sharing. Refer What is "Same Origin" Part Detailed P ...
- 《大话设计模式》num02---策略模式
2018年01月22日 22:04:57 独行侠的守望 阅读数:72更多个人分类: 设计模式编辑版权声明:本文为博主原创文章,转载请注明文章链接. https://blog.csdn.net/xiao ...
- 洛谷 P1281 书的复制
书的复制 Code: #include <iostream> #include <cstdio> #include <cstring> using namespac ...
- 2833 奇怪的梦境 未AC
2833 奇怪的梦境 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description Aiden陷入了一个奇怪的梦境:他被困在一个小 ...
- Android ImageView的几种对图片的缩放处理 解决imageview放大图片后失真问题解决办法
我的解决办法: 1 首先设置android:layout_width=”wrap_content”和android:layout_height=”wrap_content”,否则你按比例缩放后的图片放 ...
- 【Android开发笔记】程序崩溃异常总结
广播注册相关(broadcastReceiver) 没有注册广播就注销广播 注册广播但未注销广播 注册广播后重复注销广播 解决办法: 添加一个布尔变量,注册广播后为true,若为true在执行注销,注 ...
- python3基础11(正则表达式及re模块)
#生成re对象 compile# 之后再期调用 match search 返回匹配到的字符串# findall 返回匹配结果的列表#如果要对匹配的结果进行分组,可加(),并可通过\数字 去应用
- 那些年,被我蠢哭了的php代码小错误~~~
首先,我爱敲代码!!!而且我很喜欢修改bug,在看到那些bug的时候,我是兴奋的,毕竟当你解决这个bug之后感觉是很爽的. 在学习的过程中,看到无数的bug,有一些错误是很微小的,一般在PHP中都能通 ...
- vue中使用setTimeout
在vue的函数中使用setTimeout self.distroyTimeout = setTimeout(()=>{ self.initData() },1000) 这时清除setTimeou ...
- [转]Cannot deserialize the current JSON array (e.g. [1,2,3]) into type
string content =[{"id": 3636, "is_default": true, "name": "Unit&q ...