在实际开发中,碰上CPU密集且执行时间非常耗时的任务,通常我们会选择将该任务进行分割,以多线程方式同时执行若干个子任务,等这些子任务都执行完后再将所得的结果进行合并。这正是著名的map-reduce思想,不过map-reduce通常被用在分布式计算的语境下,这里举这个例子只是为了说明对多线程并发执行流程进行控制的重要性,比如某些线程必须等其他线程执行完后才能开始它的工作。使用jdk中的内置锁或者重入锁配合等待通知机制可以实现这个需求,但是会比较麻烦。因为不管是内置还是重入锁,它们关注的重点在于如何协调多线程对共享资源的访问,而不是协调特定线程的执行次序,完成复杂的并发流程控制。好在JDK在并发包下提供了CountDownLatch,CyclicBarrier,Semaphore等并发工具,可以让我们站在更高的角度思考并解决这个问题。

  map-reduce:采用"分而治之"的思想,把对大规模数据集的操作,分发给一个主节点管理下的各个分节点共同完成,然后通过整合各个节点的中间结果,得到最终结果。简单地说,MapReduce就是"任务的分解与结果的汇总"。

一、CountDownLatch(计数器)

  CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能。比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了。

构造器:

public CountDownLatch(int count) {  };  //参数count为计数值

重要方法:

public void await() throws InterruptedException { };   //调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { }; //和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
public void countDown() { }; //将count值减1

使用示例:

package com.javaBase.LineDistance;

import java.util.concurrent.CountDownLatch;

/**
* 〈一句话功能简述〉;
* 〈功能详细描述〉
*
* @author jxx
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public class TestCountDownLatch { public static void main(String[] args){
CountDownLatch countDownLatch = new CountDownLatch(2);
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
System.out.println("t1.......");
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
System.out.println("t2.......");
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t2.start();
try {
countDownLatch.await();
System.out.println("执行完成。。");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

二、CyclicBarrier(循环屏障)

  它可以实现让一组线程等待至某个状态之后再全部同时执行。叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用。我们暂且把这个状态就叫做barrier,当调用await()方法之后,线程就处于barrier了。

构造器:参数parties指让多少个线程或者任务等待至barrier状态;参数barrierAction为当这些线程都达到barrier状态时会执行的内容。

public CyclicBarrier(int parties, Runnable barrierAction) {
} public CyclicBarrier(int parties) {
}

重要方法:

public int await() throws InterruptedException, BrokenBarrierException { };
public int await(long timeout, TimeUnit unit)throws InterruptedException,BrokenBarrierException,TimeoutException { };

第一个版本比较常用,用来挂起当前线程,直至所有线程都到达barrier状态再同时执行后续任务;第二个版本是让这些线程等待至一定的时间,如果还有线程没有到达barrier状态就直接让到达barrier的线程执行后续任务。

代码实例:

package com.javaBase.LineDistance;

import java.util.concurrent.CyclicBarrier;

/**
* 〈一句话功能简述〉;
* 〈功能详细描述〉
*
* @author jxx
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public class TestCyclicBarrier { public static void main(String[] args) {
int N = 4;
CyclicBarrier barrier = new CyclicBarrier(N);
for (int i = 0; i < N; i++)
new Writer(barrier).start();
} static class Writer extends Thread {
private CyclicBarrier cyclicBarrier; public Writer(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
} @Override
public void run() {
System.out.println("线程" + Thread.currentThread().getName() + "正在写入数据...");
try {
Thread.sleep(5000); //以睡眠来模拟写入数据操作
System.out.println("线程" + Thread.currentThread().getName() + "写入数据完毕,等待其他线程写入完毕");
cyclicBarrier.await();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("所有线程写入完毕,继续处理其他任务...");
}
}
}

三、Semaphore(信号量)

  Semaphore可以控同时访问的线程个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。

构造器:

public Semaphore(int permits) {          //参数permits表示许可数目,即同时可以允许多少线程进行访问
sync = new NonfairSync(permits);
}
public Semaphore(int permits, boolean fair) { //这个多了一个参数fair表示是否是公平的,即等待时间越久的越先获取许可
sync = (fair)? new FairSync(permits) : new NonfairSync(permits);
}

重要方法:

public void acquire() throws InterruptedException {  }     //获取一个许可,若无许可能够获得,则会一直等待,直到获得许可。
public void acquire(int permits) throws InterruptedException { } //获取permits个许可
public void release() { } //释放一个许可
public void release(int permits) { } //释放permits个许可 public boolean tryAcquire() { }; //尝试获取一个许可,若获取成功,则立即返回true,若获取失败,则立即返回false
public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException { }; //尝试获取一个许可,若在指定的时间内获取成功,则立即返回true,否则则立即返回false
public boolean tryAcquire(int permits) { }; //尝试获取permits个许可,若获取成功,则立即返回true,若获取失败,则立即返回false
public boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException { }; //尝试获取permits个许可,若在指定的时间内获取成功,则立即返回true,否则则立即返回false

代码实例:

package com.javaBase.LineDistance;

import java.util.concurrent.Semaphore;

/**
* 〈一句话功能简述〉;
* 〈假若一个工厂有5台机器,但是有8个工人,一台机器同时只能被一个工人使用,只有使用完了,其他工人才能继续使用。那么我们就可以通过Semaphore来实现〉
*
* @author jxx
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public class TestSemaphore { public static void main(String[] args) {
int N = 8; //工人数
Semaphore semaphore = new Semaphore(5); //机器数目
for (int i = 0; i < N; i++)
new Worker(i, semaphore).start();
} static class Worker extends Thread {
private int num;
private Semaphore semaphore; public Worker(int num, Semaphore semaphore) {
this.num = num;
this.semaphore = semaphore;
} @Override
public void run() {
try {
semaphore.acquire();
System.out.println("工人" + this.num + "占用一个机器在生产...");
Thread.sleep(2000);
System.out.println("工人" + this.num + "释放出机器");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

四、总结

  1)CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同:

    CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行;

    而CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行;

    另外,CountDownLatch是不能够重用的,而CyclicBarrier是可以重用的。

  2)Semaphore其实和锁有点类似,它一般用于控制对某组资源的访问权限。

并发包下常见的同步工具类(CountDownLatch,CyclicBarrier,Semaphore)的更多相关文章

  1. 并发包下常见的同步工具类详解(CountDownLatch,CyclicBarrier,Semaphore)

    目录 1. 前言 2. 闭锁CountDownLatch 2.1 CountDownLatch功能简介 2.2 使用CountDownLatch 2.3 CountDownLatch原理浅析 3.循环 ...

  2. Java并发编程工具类 CountDownLatch CyclicBarrier Semaphore使用Demo

    Java并发编程工具类 CountDownLatch CyclicBarrier Semaphore使用Demo CountDownLatch countDownLatch这个类使一个线程等待其他线程 ...

  3. Java中的4个并发工具类 CountDownLatch CyclicBarrier Semaphore Exchanger

    在 java.util.concurrent 包中提供了 4 个有用的并发工具类 CountDownLatch 允许一个或多个线程等待其他线程完成操作,课题点 Thread 类的 join() 方法 ...

  4. 同步工具类 CountDownLatch 和 CyclicBarrier

    在开发中,一些异步操作会明显加快执行速度带来更好的体验,但同时也增加了开发的复杂度,想了用好多线程,就必须从这些方面去了解 线程的 wait() notify() notifyall() 方法 线程异 ...

  5. 同步工具类—— CountDownLatch

    本博客系列是学习并发编程过程中的记录总结.由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅. 并发编程系列博客传送门 CountDownLatch简介 CountDownLa ...

  6. 并发是个什么鬼之同步工具类CountDownLatch

    扯淡 写这篇文章,我先酝酿一下,实不相瞒,脱离底层太久了,更确切的情况是,真没曾认真研究过.就目前来说,很多框架包括工具类已经把实现封装的很深,你只需轻轻的调用一下API,便不费半点力气.以至于大家会 ...

  7. JUC常用同步工具类——CountDownLatch,CyclicBarrier,Semaphore

    在 JUC 下包含了一些常用的同步工具类,今天就来详细介绍一下,CountDownLatch,CyclicBarrier,Semaphore 的使用方法以及它们之间的区别. 一.CountDownLa ...

  8. java 并发工具类CountDownLatch & CyclicBarrier

    一起在java1.5被引入的并发工具类还有CountDownLatch.CyclicBarrier.Semaphore.ConcurrentHashMap和BlockingQueue,它们都存在于ja ...

  9. Java多线程同步工具类之CyclicBarrier

    一.CyclicBarrier使用 CyclicBarrier从字面上可以直接理解为线程运行的屏障,它可以让一组线程执行到一个共同的屏障点时被阻塞,直到最后一个线程执行到指定位置,你设置的执行线程就会 ...

随机推荐

  1. bi数据可视化平台带来的企业变化

    相信现在互联网的发展,大家有目共睹,在互联网的快速发展下,所产生的数据已经成为庞然大物,各行各业都在进行数据化转型,大数据分析也就成了香饽饽,bi数据可视化平台能够让数据可视化,通过数据分析可以业务人 ...

  2. java策略模式拙见

    面向对象的两个基本准则: 单一职责:一个类只有一个发生变化的原因 开闭原则:对拓展开放,对修改关闭 <Java开发手册>中,有这样的规则:超过3层的 if-else 的逻辑判断代码可以使用 ...

  3. springMVC整合mybatis,spring

    使用spring-mvc创建一个项目的过程 spring的配置十分复杂,很难记忆. 这篇博客用于记录springmvc整合创建过程,虽然步骤有点多,但是每一步都很容易理解,便于以后忘记后参考和记忆. ...

  4. 由浅入深--ORM简介

    一.ORM简介 从传统的JDBC开始说起 下面是通过JDBC连接Oracle的步骤,如下代码所示: Connection conn = null; PreparedStatement stmt = n ...

  5. HTML分块

    <!DOCTYPE html><html><head> <meta charset="utf-8"> <title>菜鸟 ...

  6. Pycharm:一直connecting to console的解决办法

    方法一: 1.打开Anaconda cmd(也就是Anaconda Prompt,在启动栏Anaconda目录里应该有)2.输入echo %PATH% 获得PATH value3.在PyCharm中, ...

  7. python字符串格式化输出 %和format举例

    #!/usr/bin/env python # -*- coding: UTF-8 -*- #pyversion:python3.5 #owner:fuzj s1 = "i am %s, i ...

  8. Chapter03 Java变量

    Chapter03 变量 目录 Chapter03 变量 3.1 为什么需要变量 3.1.1 一个程序就是一个世界 3.1.2 变量是程序的基本组成单位 3.1.3 简单原理图 3.2 变(变化)量( ...

  9. BBS项目(一)

    目录 BBS项目(一) 项目开发流程 BBS项目 BBS表分析 自关联 表关系图示 BBS项目(一) 项目开发流程 项目分类 针对互联网用户:抖音,淘宝····· 针对公司内部:后台管理系统··· 针 ...

  10. phpStudy 升级 MySQL5.7

    最新在开发项目中需要使用到mysql5.7以上版本,但是phpStudy的版本是5.5,所以需要针对MySQL升级一下 步骤  1.备份原本MySQL 备份:原本phpStudy中的MySQL文件夹改 ...