1.概述

本文主要对Java中的关于并发的类的使用写一遍Demo.

具体涉及到的类有:

  1. CountdownLatch
  2. CyclicBarrier
  3. Semaphore

2.CountdownLatch

CountdownLatch类位于java.util.concurrent包下, 利用它可以实现类似计数器的功能, 比如有一个任务C, 它需要等到任务A和任务B执行完成之后才能执行. 此时就可以利用CountdownLatch进行实现.

2-1.构造方法

public CountDownLatch(int count) {
// 省略...
}

count一般指线程的数量.

2-2.重要方法

// 调用await()方法的线程会挂起, 它会等到count=0时才继续执行
public void await() throws InterruptedException {
// 省略...
} // 与await()方法类似, 只不过是等待一段时间之后不管count值是多少, 都要继续向下执行
public boolean await(long timeout, TimeUnit unit)
throws InterruptedException {
// 省略...
} // 将count值减1
public void countDown() {
// 省略...
}

2-3.使用示例

import java.util.Random;
import java.util.concurrent.CountDownLatch; public class CountdownLatchDemo { public static void main(String[] args) {
new CountdownLatchDemo().start();
} private void start() { // 定义线程的数量
int num = 5;
CountDownLatch latch = new CountDownLatch(num);
for (int i = 0; i < num; i++) {
new Thread(new RunImpl(latch), "线程"+i).start();
} try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("所有线程写入完毕,继续处理其他任务..."); } class RunImpl implements Runnable { private CountDownLatch latch; public RunImpl(CountDownLatch latch) {
this.latch = latch;
} @Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+"正在写入数据...");
Thread.sleep(new Random().nextInt(2000)); //以睡眠来模拟写入数据操作 System.out.println(Thread.currentThread().getName()+"写入数据完毕,等待其他线程写入完毕"); // 完成任务, 计数器减1
latch.countDown();
} catch (Exception e){
e.printStackTrace();
} }
} }

输出结果如下:

线程0正在写入数据...
线程1正在写入数据...
线程2正在写入数据...
线程3正在写入数据...
线程4正在写入数据...
线程1写入数据完毕,等待其他线程写入完毕
线程4写入数据完毕,等待其他线程写入完毕
线程3写入数据完毕,等待其他线程写入完毕
线程2写入数据完毕,等待其他线程写入完毕
线程0写入数据完毕,等待其他线程写入完毕
所有线程写入完毕,继续处理其他任务...

初始化时CountDownLatch的count为5, 随后启动了5个线程, 然后调用了latch.await(), 挂起main线程, 等待5个线程执行完毕. 每个线程执行完毕时调用了latch.countDown(); 让count减1, 等到count为0时main线程继续执行.

3.CyclicBarrier

与CountdownLatch类似, 只不过它可以进行重用, 而且还可以支持任务执行完之后随即选择一个线程来执行构造方法中传入的线程任务, 还有一点不同是, 主线程main不会堵塞.

3-1.构造方法

public CyclicBarrier(int parties) {
// 省略...
} public CyclicBarrier(int parties, Runnable barrierAction) {
// 省略...
}

parties是指让多少个线程或者任务等待至barrier状态, 参数barrierAction是当所有线程都到达barrier状态时, 用最后一个到达barrier的线程执行barrierAction.

3-2.使用示例

import java.util.Random;
import java.util.concurrent.CyclicBarrier; public class CyclicBarrierDemo { public static void main(String[] args) {
new CyclicBarrierDemo().start();
} private void start() { int num = 5;
CyclicBarrier barrier = new CyclicBarrier(num, () -> System.out.println("最后调用了线程: " + Thread.currentThread().getName())); for (int i = 0; i < num; i++) {
new Thread(new RunImpl(barrier), "线程"+i).start();
} // 等待上面线程执行完后再次执行
// try {
// Thread.sleep(10000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// for (int i = 0; i < num; i++) {
// new Thread(new RunImpl(barrier), "线程"+i).start();
// } System.out.println("所有线程写入完毕,继续处理其他任务..."); } class RunImpl implements Runnable { private CyclicBarrier cyclicBarrier; public RunImpl(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
} @Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+"正在写入数据...");
Thread.sleep(new Random().nextInt(2000)); //以睡眠来模拟写入数据操作 System.out.println(Thread.currentThread().getName()+"写入数据完毕,等待其他线程写入完毕");
cyclicBarrier.await(); System.out.println(Thread.currentThread().getName()+"await()完成.");
} catch (Exception e){
e.printStackTrace();
}
}
} }

输出结果如下:

线程0正在写入数据...
线程2正在写入数据...
所有线程写入完毕,继续处理其他任务...
线程1正在写入数据...
线程3正在写入数据...
线程4正在写入数据...
线程1写入数据完毕,等待其他线程写入完毕
线程4写入数据完毕,等待其他线程写入完毕
线程2写入数据完毕,等待其他线程写入完毕
线程3写入数据完毕,等待其他线程写入完毕
线程0写入数据完毕,等待其他线程写入完毕
最后调用了线程: 线程0
线程0await()完成.
线程1await()完成.
线程2await()完成.
线程4await()完成.
线程3await()完成.

发现, main方法并不会等待所有线程执行完毕之后执行.

这里没有使用countDown()进行计数器减1, 然后使用await()方法等待计数器变为0, 而是使用await()方法, 并且在await()方法中进行计数器等于0的判断. 并且, 在所有线程到达barrier时, 用最后一个到达的线程去执行barrierAction.

4.Semaphore

Semaphore可以翻译为信号量, 它可以控制同时并发的线程数量, 通过acquire()方法获取许可, 如果没有就等待, 而release()释放一个许可, 注意: 在释放前必须先获取许可.

4-1.构造方法

public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}

permits是允许同时并发的线程数量, 而fair是控制是否允许等待时间越长的线程优先获取许可(公平与不公平).

4-2.重要方法

public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public void release() {
sync.releaseShared(1);
}

acquire()方法获取许可, release()方法释放许可.

4-3.使用示例

import java.util.Random;
import java.util.concurrent.Semaphore; public class SemaphoreDemo { public static void main(String[] args) {
new SemaphoreDemo().start();
} private void start() {
int num = 8; // 工人数
Semaphore semaphore = new Semaphore(5); // 机器数目 for (int i = 0; i < num; i++) {
new Thread(new RunImpl(i, semaphore)).start();
} } class RunImpl implements Runnable { private int num;
private Semaphore semaphore;
public RunImpl(int num, Semaphore semaphore){
this.num = num;
this.semaphore = semaphore;
} @Override
public void run() {
try {
semaphore.acquire();
System.out.println("工人" + this.num + "占用一个机器在生产...");
Thread.sleep(new Random().nextInt(2000)); // 以睡眠来模拟写入数据操作 System.out.println("工人" + this.num + "释放出机器");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} }

输出结果如下:

工人0占用一个机器在生产...
工人3占用一个机器在生产...
工人2占用一个机器在生产...
工人1占用一个机器在生产...
工人4占用一个机器在生产...
工人4释放出机器
工人5占用一个机器在生产...
工人1释放出机器
工人6占用一个机器在生产...
工人6释放出机器
工人7占用一个机器在生产...
工人5释放出机器
工人0释放出机器
工人3释放出机器
工人2释放出机器
工人7释放出机器

这里控制并发线程数量为5个, 工人多了只能等待其它工人释放机器, 再去公平/不公平竞争去使用机器.

5.总结

  1. CountDownLatch一般用于线程A等待若干个线程执行完成任务之后, 它才执行. 不可以重用.
  2. CyclicBarrier一般用于一组线程相互等待至barrier时, 先用最后一个到达的线程执行barrierAction, 再同时执行await()之后的代码. 可以重用.
  3. Semaphore其实和锁有点类似, 用于控制对某个资源的并发控制.

Java并发辅助类的使用的更多相关文章

  1. Java并发编程的4个同步辅助类

    Java并发编程的4个同步辅助类(CountDownLatch.CyclicBarrier.Semphore.Phaser) @https://www.cnblogs.com/lizhangyong/ ...

  2. Java并发编程的4个同步辅助类(CountDownLatch、CyclicBarrier、Semaphore、Phaser)

    我在<JDK1.5引入的concurrent包>中,曾经介绍过CountDownLatch.CyclicBarrier两个类,还给出了CountDownLatch的演示案例.这里再系统总结 ...

  3. Java并发编程的4个同步辅助类(CountDownLatch、CyclicBarrier、Semphore、Phaser)

    我在<jdk1.5引入的concurrent包>中,曾经介绍过CountDownLatch.CyclicBarrier两个类,还给出了CountDownLatch的演示案例.这里再系统总结 ...

  4. Java并发机制(8)--concurrent包下辅助类的使用

    Java并发编程:concurrent包下辅助类的使用 整理自:博客园-海子-http://www.cnblogs.com/dolphin0520/p/3920397.html 1.CountDown ...

  5. 【Java并发编程实战】-----“J.U.C”:CyclicBarrier

    在上篇博客([Java并发编程实战]-----"J.U.C":Semaphore)中,LZ介绍了Semaphore,下面LZ介绍CyclicBarrier.在JDK API中是这么 ...

  6. 学习笔记:java并发编程学习之初识Concurrent

    一.初识Concurrent 第一次看见concurrent的使用是在同事写的一个抽取系统代码里,当时这部分代码没有完成,有许多的问题,另一个同事接手了这部分代码的功能开发,由于他没有多线程开发的经验 ...

  7. 【Java并发编程实战】-----“J.U.C”:锁,lock

    在java中有两种方法实现锁机制,一种是在前一篇博客中([java7并发编程实战]-----线程同步机制:synchronized)介绍的synchronized,而另一种是比synchronized ...

  8. Java并发编程:CountDownLatch、CyclicBarrier和Semaphore

    Java并发编程:CountDownLatch.CyclicBarrier和Semaphore 在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch ...

  9. Java并发编程实现概览

    并发概览 >>同步 如何同步多个线程对共享资源的访问是多线程编程中最基本的问题之一.当多个线程并发访问共享数据时会出现数据处于计算中间状态或者不一致的问题,从而影响到程序的正确运行.我们通 ...

随机推荐

  1. 蓝牙协议分析(11)_BLE安全机制之SM

    1. 前言 注1:此SM是Security Manager的缩写,非彼SM,大家不要理解歪了! 书接上文,我们在“蓝牙协议分析(10)_BLE安全机制之LE Encryption”中介绍了BLE安全机 ...

  2. webapp js与安卓,ios怎么交互

    ) } } export default { callhandler (name, data, callback) { setupWebViewJavascriptBridge(function (b ...

  3. 关于Ctime库

    --------------------- 本文来自 Fuko_Ibuki 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/qq_31908675/article/de ...

  4. Android开发中Activity状态的保存与恢复

    当置于后台的Activity因内存紧张被系统自动回收的时候,再次启动它的话他会重新调用onCretae()从而丢失了之前置于后台前的状态. 这时候就要重写Activity的两个方法来保存和恢复状态,具 ...

  5. css自定义checkbox和radio样式

    很常见的问题,也有许多人写过类似的文章,自己写来记录下 css代码如下: #myCheck + label,.myRadio + label{ width:16px; height:16px; bor ...

  6. PythonStudy——进制 System of numeration

    十进制 人类天然选择了十进制. 二进制 二进制有两个特点:它由两个数码0,1组成,二进制数运算规律是逢二进一. 四进制 四进制是以4为基数的进位制,以 0.1.2 和 3 四个数字表示任何实数. 七进 ...

  7. C++ Primer Plus (Stephen Prata 著)

    第1章 预备知识 (已看) 第2章 开始学习C++ (已看) 第3章 处理数据 (已看) 第4章 复合类型 (已看) 第5章 循环和关系表达式 (已看) 第6章 分支语句和逻辑运算符 (已看) 第7章 ...

  8. Linux双线双网卡双IP双网关设置方法

    机房上架了一台测试机,系统是Ubuntu 9.04 X64的系统,母机IBM X336机器.用户需求是双线,故采用一个网卡配置电信地址,另一个网卡配置联通地址,安装好系统后配置好IP发现联通地址和电信 ...

  9. CentOS7 上学习使用docker

    一.CentOS7(64)上安装和使用docker的笔记. 1. 增加docker用户 sudo groupadd docker sudo useradd -g docker docker 2. 增加 ...

  10. Lattice并购案&我国FPGA发展路径

    FPGA作为通信.航天.军工等领域的关键核心器件,是保障国家战略安全的重要支撑基础.近年来,随着数字化.网络化和智能化的发展,FPGA的应用领域得到快速扩张.美国在FPGA领域拥有绝对的垄断优势,已成 ...