先谈谈闭锁和栅栏的区别:

1.关键区别在于,所有线程必须同时到达栅栏位置,才能继续执行。

2.闭锁用于等待某一个事件的发生,举例:CountDownLatch中await方法等待计数器为零时,所有事件才可继续执行。而栅栏是等待其他线程到位,所有事件才可继续下一步。例如:几个家庭决定在某个地方集合:“所有人6:00在麦当劳碰头,到了以后要等其他人,之后再讨论下一步要做的事情”。

Semaphore(闭锁)

这个东西和之前的synchronized干的事差不多。
synchronized保证了,我管理的那部分代码同一时刻只有一个线程能访问
Semaphore保证了,我管理的那部分代码同一时刻最多可以有n个线程访问

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore; public class SemaphoreTest {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final Semaphore sp = new Semaphore(3);
for(int i=0;i<10;i++){
Runnable runnable = new Runnable(){
public void run(){
try {
sp.acquire();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() +
"进入,当前已有" + (3-sp.availablePermits()) + "个并发");
try {
Thread.sleep((long)(Math.random()*10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() +
"即将离开");
sp.release();
//下面代码有时候执行不准确,因为其没有和上面的代码合成原子单元
System.out.println("线程" + Thread.currentThread().getName() +
"已离开,当前已有" + (3-sp.availablePermits()) + "个并发");
}
};
service.execute(runnable);
}
} }

运行结果如下:

线程pool-1-thread-2进入,当前已有2个并发
线程pool-1-thread-1进入,当前已有2个并发
线程pool-1-thread-3进入,当前已有3个并发
线程pool-1-thread-1即将离开
线程pool-1-thread-1已离开,当前已有2个并发
线程pool-1-thread-4进入,当前已有3个并发
线程pool-1-thread-3即将离开
线程pool-1-thread-3已离开,当前已有2个并发
线程pool-1-thread-5进入,当前已有3个并发
线程pool-1-thread-2即将离开
线程pool-1-thread-2已离开,当前已有2个并发
线程pool-1-thread-6进入,当前已有3个并发
线程pool-1-thread-4即将离开
线程pool-1-thread-4已离开,当前已有2个并发
线程pool-1-thread-7进入,当前已有3个并发
线程pool-1-thread-5即将离开
线程pool-1-thread-5已离开,当前已有2个并发
线程pool-1-thread-8进入,当前已有3个并发
线程pool-1-thread-8即将离开
线程pool-1-thread-9进入,当前已有3个并发
线程pool-1-thread-8已离开,当前已有3个并发
线程pool-1-thread-6即将离开
线程pool-1-thread-6已离开,当前已有2个并发
线程pool-1-thread-10进入,当前已有3个并发
线程pool-1-thread-10即将离开
线程pool-1-thread-10已离开,当前已有2个并发
线程pool-1-thread-7即将离开
线程pool-1-thread-7已离开,当前已有1个并发
线程pool-1-thread-9即将离开
线程pool-1-thread-9已离开,当前已有0个并发

参考链接:http://www.cnblogs.com/nullzx/archive/2016/03/12/5270233.html

CountDownLatch (闭锁)

它保证了什么功能呢?其实和CycliBarrier也类似。

看下面这个图

这就是CycleBarrier,线程自己管理自己,大家看到人都到齐了,才继续走。

这个是CountDownLatch,由他人来协调进度。

例如跑步的时候,有个裁判,等所有的人都到齐了,他吹哨,然后大家开始跑,等所有人都跑完了,他才公布成绩。

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class CountdownLatchTest { public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final CountDownLatch cdOrder = new CountDownLatch(1);
final CountDownLatch cdAnswer = new CountDownLatch(3);
for(int i=0;i<3;i++){
Runnable runnable = new Runnable(){
public void run(){
try {
System.out.println("线程" + Thread.currentThread().getName() +
"正准备接受命令");
cdOrder.await();
System.out.println("线程" + Thread.currentThread().getName() +
"已接受命令");
Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"回应命令处理结果");
cdAnswer.countDown();
} catch (Exception e) {
e.printStackTrace();
}
}
};
service.execute(runnable);
}
try {
Thread.sleep((long)(Math.random()*10000)); System.out.println("线程" + Thread.currentThread().getName() +
"即将发布命令");
cdOrder.countDown();
System.out.println("线程" + Thread.currentThread().getName() +
"已发送命令,正在等待结果");
cdAnswer.await();
System.out.println("线程" + Thread.currentThread().getName() +
"已收到所有响应结果");
} catch (Exception e) {
e.printStackTrace();
}
service.shutdown(); }
}

运行结果如下

线程pool-1-thread-3正准备接受命令
线程pool-1-thread-1正准备接受命令
线程pool-1-thread-2正准备接受命令
线程main即将发布命令
线程main已发送命令,正在等待结果
线程pool-1-thread-3已接受命令
线程pool-1-thread-2已接受命令
线程pool-1-thread-1已接受命令
线程pool-1-thread-3回应命令处理结果
线程pool-1-thread-1回应命令处理结果
线程pool-1-thread-2回应命令处理结果
线程main已收到所有响应结果

CountDownLatch里面有个计数器,初始值就是new countdownlatch时传入的

wait方法会一直等待,直到计数器的值变为0

coutdown方法可以让计数器的值减一

CycleBarrier(栅栏)

CycleBarrier 能做到让n个线程互相等待,当n个线程都做到某一步后,再继续下一步。

例如下面的例子,5个人去旅游,设置abc三个中途节点,所有人都到达a之后在继续走向b,所有人都到达b,然后才继续走向c。

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class CyclicBarrierTest { public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final CyclicBarrier cb = new CyclicBarrier(3);
for(int i=0;i<3;i++){
Runnable runnable = new Runnable(){
public void run(){
try {
Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"即将到达集合地点1,当前已有" + (cb.getNumberWaiting()+1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));
cb.await(); Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"即将到达集合地点2,当前已有" + (cb.getNumberWaiting()+1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));
cb.await();
Thread.sleep((long)(Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"即将到达集合地点3,当前已有" + (cb.getNumberWaiting() + 1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));
cb.await();
} catch (Exception e) {
e.printStackTrace();
}
}
};
service.execute(runnable);
}
service.shutdown();
}
}

运行结果如下:

线程pool-1-thread-2即将到达集合地点1,当前已有1个已经到达,正在等候
线程pool-1-thread-1即将到达集合地点1,当前已有2个已经到达,正在等候
线程pool-1-thread-3即将到达集合地点1,当前已有3个已经到达,都到齐了,继续走啊
线程pool-1-thread-1即将到达集合地点2,当前已有1个已经到达,正在等候
线程pool-1-thread-3即将到达集合地点2,当前已有2个已经到达,正在等候
线程pool-1-thread-2即将到达集合地点2,当前已有3个已经到达,都到齐了,继续走啊
线程pool-1-thread-1即将到达集合地点3,当前已有1个已经到达,正在等候
线程pool-1-thread-2即将到达集合地点3,当前已有2个已经到达,正在等候
线程pool-1-thread-3即将到达集合地点3,当前已有3个已经到达,都到齐了,继续走啊

Exchange(栅栏)

A线程有数据1,它需要与B线程的数据2做交换
B线程有数据2,它需要与A线程的数据1做交换

那么什么时候交换呢?得等AB都做好准备才行。

import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class ExchangerTest { public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final Exchanger<String> exchanger = new Exchanger<String>();
service.execute(new Runnable(){
public void run() {
try { String data1 = "zxx";
System.out.println("线程" + Thread.currentThread().getName() +
"正在把数据" + data1 +"换出去");
Thread.sleep((long)(Math.random()*10000));
String data2 = (String)exchanger.exchange(data1);
System.out.println("线程" + Thread.currentThread().getName() +
"换回的数据为" + data2);
}catch(Exception e){ }
}
});
service.execute(new Runnable(){
public void run() {
try { String data1 = "lhm";
System.out.println("线程" + Thread.currentThread().getName() +
"正在把数据" + data1 +"换出去");
Thread.sleep((long)(Math.random()*10000));
String data2 = (String)exchanger.exchange(data1);
System.out.println("线程" + Thread.currentThread().getName() +
"换回的数据为" + data2);
}catch(Exception e){ }
}
});
}
}

运行结果如下:

线程pool-1-thread-1正在把数据zxx换出去
线程pool-1-thread-2正在把数据lhm换出去
线程pool-1-thread-2换回的数据为zxx
线程pool-1-thread-1换回的数据为lhm

Java同步工具类总结的更多相关文章

  1. Java核心知识点学习----线程同步工具类,CyclicBarrier学习

    线程同步工具类,CyclicBarrier日常开发较少涉及,这里只举一个例子,以做备注.N个人一块出去玩,相约去两个地方,CyclicBarrier的主要作用是等待所有人都汇合了,才往下一站出发. 1 ...

  2. 《java并发编程实战》读书笔记4--基础构建模块,java中的同步容器类&并发容器类&同步工具类,消费者模式

    上一章说道委托是创建线程安全类的一个最有效策略,只需让现有的线程安全的类管理所有的状态即可.那么这章便说的是怎么利用java平台类库的并发基础构建模块呢? 5.1 同步容器类 包括Vector和Has ...

  3. java 利用同步工具类控制线程

    前言 参考来源:<java并发编程实战> 同步工具类:根据工具类的自身状态来协调线程的控制流.通过同步工具类,来协调线程之间的行为. 可见性:在多线程环境下,当某个属性被其他线程修改后,其 ...

  4. Java多线程同步工具类之CountDownLatch

    在过去我们实现多线程同步的代码中,往往使用join().wait().notiyAll()等线程间通信的方式,随着JUC包的不断的完善,java为我们提供了丰富同步工具类,官方也鼓励我们使用工具类来实 ...

  5. Java并发之同步工具类

    1. CountDownlatch(计数器) 描述: 一个同步工具类,允许一个或多个线程等待其它线程完成操作 类图 通过指定的count值进行初始化,调用await方法的线程将被阻塞,直到count值 ...

  6. Java并发(基础知识)——显示锁和同步工具类

    显示锁                                                                                     Lock接口是Java ...

  7. java.util.concurrent中的几种同步工具类

    java.util.concurrent并发包中提供了一系列的的同步工具类,这些基础类不管是否能在项目中使用到,了解一下使用方法和原理对java程序员来说都是有必要的.博主在看<java并发编程 ...

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

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

  9. Java并发工具类(一):等待多线程完成的CountDownLatch

    作用 CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行 简介 CountDownLatch是在java1.5被引入的,存在于java.uti ...

随机推荐

  1. js获取标签的几种方式

    一:id获取(全部浏览器兼容) document.getElementById(""); <body> <div id="box">&l ...

  2. PowerDesigner 的7种建模文件

    1.  概念数据模型 (CDM) 对数据和信息进行建模,利用实体-关系图(E-R图)的形式组织数据,检验数据设计的有效性和合理性. 2.  逻辑数据模型 (LDM) PowerDesigner 15 ...

  3. jQuery慢慢啃筛选(四)

    1.eq(index|-index) 获取第N个元素 其中负数:一个整数,指示元素的位置,从集合中的最后一个元素开始倒数.(1算起) $("p").eq(1)//获取匹配的第二个元 ...

  4. dedecms 文章内容文章名字和文章网址的调用

    文章标题: <a href="{dede:field name='arcurl'/}">{dede:field.title/}</a> 本文章网址: < ...

  5. Josephus2

    约瑟夫问题升级问题 编号为1~N的N个人按顺时针方向围坐一圈,每个人持有一个密码(正整数,可以自由输入),开始人选一个正整数作为报数上限值M,从第一个人按顺时针方向自1开始顺序报数,报道M是停止报数. ...

  6. android开发学习笔记:圆角的Button

    转自:http://www.cnblogs.com/gzggyy/archive/2013/05/17/3083218.html 在res目录下的drawable-mdpi建立xml文件shape.x ...

  7. An endpoint configuration section for contract "serviceReferenc.service" could not be loaded

    场景:有一个WCF应用,添加服务引用后,自动生成一个app.config文件,当调用WCF时,它抛出一个错误: An endpoint configuration section for contra ...

  8. nutch,hbase,zookeeper兼容性问题

    nutch-2.1使用gora-0.2.1, gora-0.2.1使用hbase-0.90.4,hbase-0.90.4和hadoop-1.1.1不兼容,hbase-0.94.4和gora-0.2.1 ...

  9. angular2 学习笔记 (Pipes)

    Pipe 就是 ng1 的 filter <pre>{{ jsonValue | json }}</pre> 用法看这里就很清楚了 : https://angular.cn/d ...

  10. STM8S 模拟I2C程序

    STM8S的硬件I2C还是存在问题,不敢贸然使用. 于是决定用模拟I2C. #define SCL PE_ODR_ODR1 #define SDA PE_ODR_ODR2 #define SDAM P ...