java 并发实例_java一些常用并发工具示例
最近把《java并发编程实战》-Java Consurrency in Practice 重温了一遍,把书中提到的一些常用工具记录于此:
一、闭锁(门栓)- CountDownLatch
适用场景:多线程测试时,通常为了精确计时,要求所有线程都ready后,才开始执行,防止有线程先起跑,造成不公平,类似的,所有线程执行完,整个程序才算运行完成。
/**
* 闭锁测试(菩提树下的杨过 http://yjmyzz.cnblogs.com/)
*
* @throws InterruptedException
*/
@Test
public void countdownLatch() throws InterruptedException {
CountDownLatch startLatch = new CountDownLatch(1); //类似发令枪
CountDownLatch endLatch = new CountDownLatch(10);//这里的数量,要与线程数相同
for (int i = 0; i < 10; i++) {
Thread t = new Thread(() -> {
try {
startLatch.await(); //先等着,直到发令枪响,防止有线程先run
System.out.println(Thread.currentThread().getName() + " is running...");
Thread.sleep(10);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
endLatch.countDown(); //每个线程执行完成后,计数
}
});
t.setName("线程-" + i);
t.start();
}
long start = System.currentTimeMillis();
startLatch.countDown();//发令枪响,所有线程『开跑』
endLatch.await();//等所有线程都完成
long end = System.currentTimeMillis();
System.out.println("done! exec time => " + (end - start) + " ms");
}
执行结果:
线程-1 is running...
线程-5 is running...
线程-8 is running...
线程-4 is running...
线程-3 is running...
线程-0 is running...
线程-2 is running...
线程-9 is running...
线程-7 is running...
线程-6 is running...
done! exec time => 13 ms
注:大家可以把第14行注释掉,再看看运行结果有什么不同。
二、信号量(Semaphore)
适用场景:用于资源数有限制的并发访问场景。
public class BoundedHashSet {
private final Set set;
private final Semaphore semaphore;
public BoundedHashSet(int bound) {
this.set = Collections.synchronizedSet(new HashSet());
this.semaphore = new Semaphore(bound);
}
public boolean add(T t) throws InterruptedException {
if (!semaphore.tryAcquire(5, TimeUnit.SECONDS)) {
return false;
}
;
boolean added = false;
try {
added = set.add(t);
return added;
} finally {
if (!added) {
semaphore.release();
}
}
}
public boolean remove(Object o) {
boolean removed = set.remove(o);
if (removed) {
semaphore.release();
}
return removed;
}
}
@Test
public void semaphoreTest() throws InterruptedException {
BoundedHashSet set = new BoundedHashSet<>(5);
for (int i = 0; i < 6; i++) {
if (set.add(i + "")) {
System.out.println(i + " added !");
} else {
System.out.println(i + " not add to Set!");
}
}
}
上面的示例将一个普通的Set变成了有界容器。执行结果如下:
0 added !
1 added !
2 added !
3 added !
4 added !
5 not add to Set!
三、栅栏CyclicBarrier
这个跟闭锁类似,可以通过代码设置一个『屏障』点,其它线程到达该点后才能继续,常用于约束其它线程都到达某一状态后,才允许做后面的事情。
public class Worker extends Thread {
private CyclicBarrier cyclicBarrier;
public Worker(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
private void step1() {
System.out.println(this.getName() + " step 1 ...");
}
private void step2() {
System.out.println(this.getName() + " step 2 ...");
}
public void run() {
step1();
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
step2();
}
}
@Test
public void cyclicBarrierTest() throws InterruptedException, BrokenBarrierException {
CyclicBarrier cyclicBarrier = new CyclicBarrier(11);
for (int i = 0; i < 10; i++) {
Worker w = new Worker(cyclicBarrier);
w.start();
}
cyclicBarrier.await();
}
这里我们假设有一个worder线程,里面有2步操作,要求所有线程完成step1后,才能继续step2. 执行结果如下:
Thread-0 step 1 ...
Thread-1 step 1 ...
Thread-2 step 1 ...
Thread-3 step 1 ...
Thread-4 step 1 ...
Thread-5 step 1 ...
Thread-6 step 1 ...
Thread-7 step 1 ...
Thread-8 step 1 ...
Thread-9 step 1 ...
Thread-9 step 2 ...
Thread-0 step 2 ...
Thread-3 step 2 ...
Thread-4 step 2 ...
Thread-6 step 2 ...
Thread-2 step 2 ...
Thread-1 step 2 ...
Thread-8 step 2 ...
Thread-7 step 2 ...
Thread-5 step 2 ...
四、Exchanger
如果2个线程需要交换数据,Exchanger就能派上用场了,见下面的示例:
@Test
public void exchangerTest() {
Exchanger exchanger = new Exchanger<>();
Thread t1 = new Thread(() -> {
String temp = "AAAAAA";
System.out.println("thread 1 交换前:" + temp);
try {
temp = exchanger.exchange(temp);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread 1 交换后:" + temp);
});
Thread t2 = new Thread(() -> {
String temp = "BBBBBB";
System.out.println("thread 2 交换前:" + temp);
try {
temp = exchanger.exchange(temp);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread 2 交换后:" + temp);
});
t1.start();
t2.start();
}
执行结果:
thread 1 交换前:AAAAAA
thread 2 交换前:BBBBBB
thread 2 交换后:AAAAAA
thread 1 交换后:BBBBBB
五、FutureTask/Future
一些很耗时的操作,可以用Future转化成异步,不阻塞后续的处理,直到真正需要返回结果时调用get拿到结果
@Test
public void futureTaskTest() throws ExecutionException, InterruptedException, TimeoutException {
Callable callable = () -> {
System.out.println("很耗时的操作处理中。。。");
Thread.sleep(5000);
return "done";
};
FutureTask futureTask = new FutureTask<>(callable);
System.out.println("就绪。。。");
new Thread(futureTask).start();
System.out.println("主线程其它处理。。。");
System.out.println(futureTask.get());
System.out.println("处理完成!");
System.out.println("-----------------");
System.out.println("executor 就绪。。。");
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future future = executorService.submit(callable);
System.out.println(future.get(10, TimeUnit.SECONDS));
}
执行结果:
就绪。。。
主线程其它处理。。。
很耗时的操作处理中。。。
done
处理完成!
-----------------
executor 就绪。。。
很耗时的操作处理中。。。
done
六、阻塞队列BlockingQueue
阻塞队列可以在线程间实现生产者-消费者模式。比如下面的示例:线程producer模拟快速生产数据,而线程consumer模拟慢速消费数据,当达到队列的上限时(即:生产者产生的数据,已经放不下了),队列就堵塞住了。
@Test
public void blockingQueueTest() throws InterruptedException {
final BlockingQueue blockingDeque = new ArrayBlockingQueue<>(5);
Thread producer = new Thread() {
public void run() {
Random rnd = new Random();
while (true) {
try {
int i = rnd.nextInt(10000);
blockingDeque.put(i + "");
System.out.println(this.getName() + " 产生了一个数字:" + i);
Thread.sleep(rnd.nextInt(50));//模拟生产者快速生产
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
};
producer.setName("producer 1");
Thread consumer = new Thread() {
public void run() {
while (true) {
Random rnd = new Random();
try {
String i = blockingDeque.take();
System.out.println(this.getName() + " 消费了一个数字:" + i);
Thread.sleep(rnd.nextInt(10000));//消费者模拟慢速消费
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
};
consumer.setName("consumer 1");
producer.start();
consumer.start();
while (true) {
Thread.sleep(100);
}
}
执行结果:
producer 1 产生了一个数字:6773
consumer 1 消费了一个数字:6773
producer 1 产生了一个数字:4456
producer 1 产生了一个数字:8572
producer 1 产生了一个数字:5764
producer 1 产生了一个数字:2874
producer 1 产生了一个数字:780 # 注意这里就已经堵住了,直到有消费者消费一条数据,才能继续生产
consumer 1 消费了一个数字:4456
producer 1 产生了一个数字:4193
java 并发实例_java一些常用并发工具示例相关推荐
- java 多线程 并发实例_Java 多线程(并发)
线程释义 使用java.lang.Thread类或者java.lang.Runnable接口编写代码来定义.实例化和启动新线程. 一个Thread类实例只是一个对象,像Java中的任何其他对象一样,具 ...
- java final 实例_Java中final实现原理的深入分析(附示例)
本篇文章给大家带来的内容是关于Java中final实现原理的深入分析(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. final在Java中是一个保留的关键字,可以声明成员变 ...
- Java软件开发中,常用的工具有哪些?
学习Java知识点不足以用于实践.想要操作,需要知道Java开发工具有哪些.掌握Java开发工具的使用,才能熟练地写出代码编程.可说,没有得心应手的工具,想要做好Java开发,就有了一定的难度,所以今 ...
- java开发任务必备的工具_Web常用开发工具有哪些?常用工具推荐
Web常用开发工具有哪些?常用工具推荐,IT程序员为了快速.高效地完成任务,会使用一些Web开发具来辅助完成工作,这些工具有代码高亮显示.语法提示等便捷功能的前端开发工具,对于开发者非常友好. 小编整 ...
- Java程序员开发编程常用的工具
1.常用开发工具 作为一名Java程序开发人员,可以的选择集成开发环境IDE(Integrated Development Environment)非常多,得益于Java是一门开源语言.有开源免费的: ...
- java多线程并发实例_JAVA多线程的并发控制|java多线程并发实例
java的多线程实现主要有两种,一种是继承Thread,一种是实现Runnable接口,这个是java最基本的多线程知识.这里要补充一下,runnable接口中的run方法是不返回任何内容的,如果想返 ...
- java多线程面试_Java多线程和并发基础面试问答,看过后你不会后悔
***:Java多线程面试问题 1:进程和线程之间有什么不同? 一个进程是一个独立(self contained)的运行环境,它可以被看作一个程序或者一个应用.而线程是在进程中执行的一个任务.Java ...
- java 多线程并发 问题_JAVA多线程和并发基础面试问答
原文链接 译文连接作者:Pankaj 译者:郑旭东 校对:方腾飞 多线程和并发问题是Java技术面试中面试官比较喜欢问的问题之一.在这里,从面试的角度列出了大部分重要的问题,但是你仍然应该牢固的掌 ...
- java多线程 门闩_Java线程与并发编程实践----同步器(倒计时门闩,同步屏障)...
Java提供的synchronized关键字对临界区进行线程同步访问.由于基于synchronized很难 正确编写同步代码,并发工具类提供了高级的同步器.倒计时门闩(countdown latch) ...
最新文章
- 单目深度估计与伪雷达点云、可视化
- 转:SAP 零售业POS心得分享
- JVM学习笔记(三)------内存管理和垃圾回收
- OpenGL保守光栅化
- Java应用程序中的验证
- Adobe Dreamweaver 添加库、标签和属性
- 平流式隔油池计算_海淀区平流式隔油池厂家供货
- 读书笔记-穿越计算机的迷雾
- CentOS修改时间和时区
- WEB自动化学习路线(转载)
- CNZZ是统计什么的
- Leetcode 905. Sort Array By Parity
- byte最大值最小值的问题
- python 爬取动漫之家,下载漫画
- Vue.filter过滤器存储单位换算按B、KB 、M、 G显示字节大小
- arduino 源码分层浅析
- 爬虫爬取音乐url大全
- 如果,我是说如果 可以
- MATLAB 基础笔记(一):数组的生成
- vue 单一页面_带有vue的单一Flash消息
热门文章
- 焊接工具DIY电焊机,自动触发笔,手持电焊笔
- CSDN写作Markdown编辑器中的Python命令帮手
- 拆解一个舵机组成的机器人
- 通用双谐振固态特斯拉驱动器 UD2.7
- BPW-21光电二极管的特性测试
- php的优势和背景,CSS_CSS 多图片融合背景定位的应用于优缺点分析,1. 关键字, 例如: background-positio - phpStudy...
- php 语句插入失败,php – Mysqli准备语句插入不插入
- java 判断时间合法_java 中 Date 类型快判断日期是否合法.
- matlab 两列数据相乘,在EXCEL中,两列完全相同的数据,求和结果不一样??单元格两列相乘的公式...
- 连接redis的linux命令,redis常见操作命令