Java为我们提供了一些同步辅助类,利用这些辅助类我们可以在多线程编程中,灵活地把握线程的状态。

CountDownLatch

CountDownLatch一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。

再CountDownLatch中两个比较关键的方法:

public void await() throws InterruptedException;
public void countDown();

CountDownLatch是一个计数器,它的构造方法中需要设置一个数值,用来设定计数的次数。每次调用countDown()方法之后,这个计数器都会减去1,CountDownLatch会一直阻塞着调用await()方法的线程,直到计数器的值变为0

设想有这样一个功能需要Thread1、Thread2、Thread3、Thread4四条线程分别统计C、D、E、F四个盘的大小,所有线程都统计完毕交给主线程去做汇总,利用CountDownLatch来完成就非常轻松。

public class CountDownLatchTest {private static CountDownLatch count = new CountDownLatch(4);private static ExecutorService service = Executors.newFixedThreadPool(6);public static void main(String args[]) throws InterruptedException {for (int i = 0; i < 4; i++) {service.execute(() -> {// 模拟任务耗时try {int timer = new Random().nextInt(5);TimeUnit.SECONDS.sleep(timer);System.out.printf("%s时完成磁盘的统计任务,耗费%d秒.\n", new Date().toString(), timer);// 任务完成之后,计数器减一count.countDown();} catch (InterruptedException e) {e.printStackTrace();}});}// 主线程一直被阻塞,知道count的计数器被设置为0count.await();System.out.printf("%s时全部任务都完成,执行合并计算.\n", new Date().toString());service.shutdown();}
}

CyclicBarrier

Barrier在英语中是屏障的意思,这个同步工具会阻塞调用的线程,直到条件满足时,阻塞的线程同时被打开。

public int await() throws InterruptedException, BrokenBarrierException

CyclicBarrier初始化的时候,设置一个屏障数。线程调用await()方法的时候,这个线程就会被阻塞,当调用await()的线程数量到达屏障数的时候,主线程就会取消所有被阻塞线程的状态。

CyclicBarrier的构造方法中,还可以设置一个barrierAction

在所有的屏障都到达之后,会启动一个线程来运行这里面的代码。这里举一个例子:百米赛跑的运动员起跑前需要准备,所有选手准备完毕之后,才可以同时起跑。

public class CyclicBarrierTest {private static CyclicBarrier cyclicBarrier = new CyclicBarrier(8);private static ExecutorService service = Executors.newFixedThreadPool(50);public static void main(String args[]) {for (int i = 1; i < 9; i++) {service.execute(new Thread(new Runner(i, cyclicBarrier)));}service.shutdown();}
}
// 运动员类
public class Runner implements Runnable {private int number;private CyclicBarrier cyclicBarrier;public Runner(int number, CyclicBarrier cyclicBarrier) {this.number = number;this.cyclicBarrier = cyclicBarrier;}@Overridepublic void run() {try {int timer = new Random().nextInt(5);TimeUnit.SECONDS.sleep(timer);System.out.printf("%d号选手准备完毕,准备时间%d\n", number, timer);cyclicBarrier.await();System.out.printf("%d号选手于%s时起跑!\n", number, new Date().toString());} catch (InterruptedException | BrokenBarrierException e) {e.printStackTrace();}}
}

输出:

1号选手准备完毕,准备时间0
4号选手准备完毕,准备时间0
5号选手准备完毕,准备时间1
8号选手准备完毕,准备时间1
3号选手准备完毕,准备时间2
2号选手准备完毕,准备时间3
7号选手准备完毕,准备时间3
6号选手准备完毕,准备时间3
7号选手于Sun Mar 27 21:19:00 CST 2016时起跑!
2号选手于Sun Mar 27 21:19:00 CST 2016时起跑!
5号选手于Sun Mar 27 21:19:00 CST 2016时起跑!
6号选手于Sun Mar 27 21:19:00 CST 2016时起跑!
3号选手于Sun Mar 27 21:19:00 CST 2016时起跑!
8号选手于Sun Mar 27 21:19:00 CST 2016时起跑!
4号选手于Sun Mar 27 21:19:00 CST 2016时起跑!
1号选手于Sun Mar 27 21:19:00 CST 2016时起跑!

相比CountDownLatchCyclicBarrier是可以被循环使用的,而且遇到线程中断等情况时,还可以利用reset()方法,重置计数器,从这些方面来说,CyclicBarrier会比CountDownLatch更加灵活一些。

Semaphore

Semaphore被用于控制特定资源在同一个时间被访问的个数。类似连接池的概念,保证资源可以被合理的使用。

Semaphore的几个重要方法:

// 获取资源
public void acquire() throws InterruptedException
// 释放资源
public void release()

Semaphore的构造方法可以设置一个int值来设置一个计数器,用于表示资源同时可以被多少外部环境使用。每使用一次acquire(),计数器都会去减去一,而每次调用release()计数器则会增加一。当计数器的值为0的时候,外部的环境被阻塞,直到Semaphore有空闲的资源可以被使用。

public class SemaphoreTest {private static Semaphore semaphore = new Semaphore(3);private static ExecutorService service = Executors.newFixedThreadPool(6);public static void main(String args[]) {// 执行9个任务for (int i = 0; i < 9; i++) {service.execute(() -> {try {semaphore.acquire();System.out.printf("%s时获取资源,并调用.\n", new Date().toString());// 线程挂起3秒TimeUnit.SECONDS.sleep(3);semaphore.release();} catch (InterruptedException e) {e.printStackTrace();}});}service.shutdown();}
}

运行的结果就是:

Sun Mar 27 20:18:16 CST 2016时获取资源,并调用.
Sun Mar 27 20:18:16 CST 2016时获取资源,并调用.
Sun Mar 27 20:18:16 CST 2016时获取资源,并调用.
Sun Mar 27 20:18:19 CST 2016时获取资源,并调用.
Sun Mar 27 20:18:19 CST 2016时获取资源,并调用.
Sun Mar 27 20:18:19 CST 2016时获取资源,并调用.
Sun Mar 27 20:18:22 CST 2016时获取资源,并调用.
Sun Mar 27 20:18:22 CST 2016时获取资源,并调用.
Sun Mar 27 20:18:22 CST 2016时获取资源,并调用.

虽然线程池允许6个最大线程数量,但是同一个时间内只用三个任务被执行。

转载于:https://www.cnblogs.com/whthomas/p/java_concurrent_tools.html

Java的几个同步辅助类相关推荐

  1. Java中的5种同步辅助类

    当你使用synchronized关键字的时候,是通过互斥器来保障线程安全以及对共享资源的同步访问.线程间也经常需要更进一步的协调执行,来完成复杂的并发任务,比如wait/notify模式就是一种在多线 ...

  2. CountDownLatch,同步辅助类

    public class CountDownLatchextends Object一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待. 假设定义一个计数器为 5. 每 ...

  3. java中同步_在Java中的方法同步和语句同步(块同步) - Break易站

    Java 多线程 线程主要通过共享对字段的访问和参考字段引用的对象进行通信.这种通信形式非常有效,但可能出现两种错误:线程干扰和内存一致性错误.需要一些同步构造来防止这些错误.以下示例显示了我们需要同 ...

  4. java中什么是同步_Java中,“synchronized”(同步)是什么意思?什么时候应该用synchronized? - Break易站...

    synchronized关键字的意义是什么? 什么时候应该是方法synchronized? 这是什么编程和逻辑? Java中,"synchronized"(同步)是什么意思?什么时 ...

  5. java异步接口转同步接口_如果今天设计了Java:同步接口

    java异步接口转同步接口 Java已经走了很长一段路. 很长的路要走. 它带有早期设计决策中的所有"垃圾". 一遍又一遍后悔的一件事是, 每个对象(可能)都包含一个监视器 . 几 ...

  6. Java7并发编程指南——第三章:线程同步辅助类

    Java7并发编程指南--第三章:线程同步辅助类 @(并发和IO流) Java7并发编程指南第三章线程同步辅助类 思维导图 项目代码 思维导图 项目代码 GitHub:Java7Concurrency ...

  7. java每一个小时同步_Java同步块(synchronized block)使用详解

    Java 同步块(synchronized block)用来标记方法或者代码块是同步的.Java同步块用来避免竞争.本文介绍以下内容: Java同步关键字(synchronzied) 实例方法同步 静 ...

  8. java多线程采集+线程同步-【多线程数据采集之四】

    前些日子讲解了java数据抓取, 今天就讲解最核心的. java多线程数据抓取. java多线程采集+数据同步+线程同步[多线程数据采集之四] 主要讲解多线程抓取,多线程同步,多线程启动,控制等操作. ...

  9. java 线程 john_教你Java开发中多线程同步技巧

    教你Java开发中多线程同步技巧 在编写一个类时,如果该类中的代码可能运行于多线程环境下,那么就要考虑同步的问题.在Java中内置了语言级的同步原语--synchronized,这也大大简化了Java ...

最新文章

  1. 拾谈“用最有效率的方法算出2乘以8等於几?”
  2. 华为pat地址转换,以及内网web服务器发布
  3. Javascript 中变更Html标签label的文本
  4. ZYNQ中断示例修改
  5. 小小攻城师,步步达成梦想!
  6. RAID 0、1、5、1+0总结
  7. 使用未初始化的内存是什么意思_他们都说JVM能实际使用的内存比-Xmx指定的少?这是为什么呢...
  8. P2249 【深基13.例1】查找(AC) 2022.1.28
  9. [上架] iOS 上架更新版本号建议
  10. Q1:spring-boot中Controller路径无法被访问的问题
  11. oracle 得到父节点和子节点
  12. mpq算法实现哈希查找
  13. Android下实现Google街景
  14. 计算机游戏屏幕中,电脑屏幕上的游戏怎么录制
  15. c语言进行数据统计分析的研究报告,【干货分享】CCTS:临床试验统计分析计划及统计分析报告...
  16. 经常听到卡农吧,可是你知道卡农背后的含义么?
  17. 前端导出表格,万级数据,带样式(留自用)
  18. Unity3D 学习笔记3——了解U3D引擎的操作面板和各种工具
  19. 《名侦探柯南》中的“IoT恐袭”
  20. 信息安全等级测评师考试重点梳理

热门文章

  1. 为Mac OS X添加用Firefox搜索服务
  2. 百万记录级MySQL数据库及Discuz!论坛优化
  3. 数据备份、pymysql模块
  4. 19.C++-(=)赋值操作符、初步编写智能指针
  5. Cacti 使用安装详解-企业级实例
  6. Oracle conn 协议适配器错误解决
  7. 如何使用js动态显示或隐藏DIV
  8. 数据结构与算法--2.数组的定位排序
  9. android object数组赋值_Java对象数组定义与用法详解
  10. TensorFlow 简介