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的计数器被设置为0
count.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;
} @Override
public 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个最大线程数量,但是同一个时间内只用三个任务被执行。

Java的几个同步辅助类的更多相关文章

  1. Java并发编程之同步辅助类

    CountDownLatch 在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待,基于AbstractQueuedSynchronizer实现,state初始化为count,每cou ...

  2. JAVA线程同步辅助类CountDownLatch

    一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待. 用给定的计数 初始化 CountDownLatch.由于调用了 countDown() 方法,所以在当前计数到达 ...

  3. JAVA线程同步辅助类CyclicBarrier循环屏障

    CyclicBarrier是一个同步辅助类,主要作用是让一组线程互相等待,知道都到达一个公共障点,在一起走.在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrie ...

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

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

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

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

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

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

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

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

  8. java并发之同步辅助类(Semphore、CountDownLatch、CyclicBarrier、Phaser)

    线程同步辅助类,主要学习两点: 1.上述几种同步辅助类的作用以及常用的方法 2.适用场景,如果有适当的场景可以用到,那无疑是最好的 semaphore(seməˌfôr) 含义 信号量就是可以声明多把 ...

  9. 同步辅助类CountDownLatch用法

    CountDownLatch是一个同步辅助类,犹如倒计时计数器,创建对象时通过构造方法设置初始值,调用CountDownLatch对象的await()方法则使当前线程处于等待状态,调用countDow ...

随机推荐

  1. Vagrant 基础全面解析

    这篇 Vagrant 入门文章将带你创建一个 Vagrant 项目,这个过程将会用到 Vagrant 所提供的主要基本特性.如果想了解 Vagrant 能为你带来哪些好处,可以阅读 Vagrant 官 ...

  2. UWP 律师查询 MVVM

    APP简介 律师查询是基于聚合数据的律师查询接口做的,这个接口目前处于停用状态,但是,由于我是之前申请的,所以,还可以用,应该是无法再申请了. 效果图 开发 一.HttpHelper 既然是请求接口的 ...

  3. 懒加载session 无法打开 no session or session was closed 解决办法(完美解决)

           首先说明一下,hibernate的延迟加载特性(lazy).所谓的延迟加载就是当真正需要查询数据时才执行数据加载操作.因为hibernate当中支持实体对象,外键会与实体对象关联起来.如 ...

  4. C# - 值类型、引用类型&走出误区,容易错误的说法

    1. 值类型与引用类型小总结 1)对于引用类型的表达式(如一个变量),它的值是一个引用,而非对象. 2)引用就像URL,是允许你访问真实信息的一小片数据. 3)对于值类型的表达式,它的值是实际的数据. ...

  5. ASP.NET MVC5+EF6+EasyUI 后台管理系统 (源码购买说明)

    系列目录 升级日志 !!!重大版本更新:于2016-12-20日完成了系统的结构重构并合并简化了T4(这是一次重要的更新,不需要修改现有功能的代码),代码总行数比上个版本又少了1/3.更新了代码生成器 ...

  6. ZKWeb网页框架1.2正式发布

    发行日志 https://github.com/zkweb-framework/ZKWeb/blob/master/ReleaseNotes/ReleaseNote.1.2.md 主要改动 更新 ZK ...

  7. [开发笔记] Graph Databases on developing

    TimeWall is a graph databases github It be used to apply mathematic model and social network with gr ...

  8. npm 使用小结

    本文内容基于 npm 4.0.5 概述 npm (node package manager),即 node 包管理器.这里的 node 包就是指各种 javascript 库. npm 是随同 Nod ...

  9. 利用Select2优化@Html.ListBoxFor显示,学会用MultiSelectList

    最近需要用到多选框,Asp.Net MVC自带的@Html.ListBox或@Html.ListBoxFor的显示效果太差,于是找到了Select2进行优化,并正式了解了多选框的操作方法. 首先介绍多 ...

  10. C++整数转字符串的一种方法

    #include <sstream> //ostringstream, ostringstream::str() ostringstream stream; stream << ...