JUC(java.util.concurrent包)中的几种同步工具类
| 类 | 用途 | 主要方法 | |
|---|---|---|---|
| 1 | Semaphore | 信号量 用来来控制同时对某个特定资源的访问或操作数量,例如池化技术(连接池)的并发数,有界阻塞容器的容量等; 二值信号量(初始值为1的信号量)可以被用作互斥体; | public void acquire()方法获得许可(阻塞方法,直到拿到许可)public boolean tryAcquire()尝试获得1个许可,立即返回。成功true,失败false;public boolean tryAcquire(long timeout, TimeUnit unit)在给定时间内尝试获取1个许可; public void release()方法释放许可;public int availablePermits() 获取可用许可的个数; |
| 2 | CountDownLatch | 闭锁 延迟线程的进度,直到闭锁达到其终止状态;可以用来确保某些活动直到某些其他活动都完成后才继续进行下去; 闭锁是一次性的,进入终态后不可重置; 闭锁用于等待事件,多用于一个线程等待其他线程; | public CountDownLatch(int count) 构造函数,参数为计数器的个数;public void await() 在计数器变为0之前,将在此一直等待;public boolean await(long timeout, TimeUnit unit) 在指定时间内若计数值变为0,则返回true,否则返回false;public void countDown() 当计数器的计数>0时,减一; |
| 3 | CyclicBarrier | 栅栏 与闭锁相比,栅栏可以反复重置使用; 用于等待其他线程,多用于多个线程相互等待 | public CyclicBarrier(int parties);public CyclicBarrier(int parties, Runnable barrierAction)public int await() //一直等待直到足够多的线程parties都调用了此方法,大家一起通过此位置。 |
| 4 | Exchanger | 一种两方栅栏(Two-Party)。 适用于两个线程同步交换数据 | public V exchange(V x)参数x本线程要送出去的数据,返回别的线程的信息。 |
| 5 | Phaser | java1.7后加入,功能强大,可以用来替代闭锁CountDownLatch和栅栏CyclicBarrier |
工具类使用方法
1. Semaphore测试代码
package com.example.conncurrency;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.*;
/**
* 信号量Test:
*
* acquire()方法获得许可;//阻塞方法,直到拿到许可
*
* release()方法释放许可;//release()后增加一个许可,不受创建时的初始值限制!!!!!
*
* 二值信号量(初始值为1的信号量)可以用作互斥体;
*
* 可用于控制对特定资源的访问数量,例如池化技术(连接池)的并发数,以及有界阻塞容器的容量等;
*/
public class SemaphoreTest {
public static void main(String[] args){
//ExecutorService executorService=new ThreadPoolExecutor(3,5,60,TimeUnit.SECONDS,new LinkedBlockingDeque<>(10));
BoundedHashSet<Integer> boundedHashSet=new BoundedHashSet<>(5);
for(int i=0; i<6; ++i){
try {
boundedHashSet.add(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(boundedHashSet.size());
}
System.out.println("如果阻塞将走不到这里。");
}
}
/**
* 使用信号量为容器设置边界。可以使用Semaphore将任何一种容器变成有界阻塞容器。
* @param <T>
*/
class BoundedHashSet<T>{
private final Set<T> set;
private final Semaphore semaphore;
BoundedHashSet(int bound) {
this.set = Collections.synchronizedSet(new HashSet<T>());
semaphore = new Semaphore(bound);
}
public boolean add(T o) throws InterruptedException {
semaphore.acquire();//阻塞方法
//semaphore.tryAcquire();//即刻返回一个bool类型的值,代表获取许可是否成功
boolean wasAdded =false;
try{
wasAdded=set.add(o);
return wasAdded;
}
finally {
if(!wasAdded){
semaphore.release();
}
}
}
public boolean remove(Object o){
boolean wasRemoved=set.remove(o);
if(wasRemoved){
semaphore.release();//release()后增加一个许可,不受创建时的初始值限制!!!!!
}
return wasRemoved;
}
public int size(){
return this.set.size();
}
}
执行结果↓:

2. CountDownLatch测试代码
package com.example.conncurrency;
import java.sql.Time;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.*;
/**
* 闭锁Test。
*/
public class CountDownLatchTest {
public static void main(String[] args) throws InterruptedException {
//ExecutorService executorService = new ThreadPoolExecutor(10,20,60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10));
int threadCount=5;
//闭锁
final CountDownLatch startGate=new CountDownLatch(1);
final CountDownLatch endGate=new CountDownLatch(threadCount);
for(int i=0; i<threadCount; ++i){
//模拟一些可能消耗时间的操作
TimeUnit.SECONDS.sleep(1);
final int index = i;
//STEP 1 提交任务
//executorService.execute(new Runnable() {
new Thread("thread_"+index){
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+"准备好了!等待信号枪..."+new Date());
//STEP 2 等待放行
startGate.await();//等待任务提交线程放行。适用于性能测试时模拟并发测试。
//STEP 4
System.out.println(Thread.currentThread().getName()+"开始跑!"+new Date());
TimeUnit.SECONDS.sleep(new Random(index).nextInt(5));//模拟线程的处理耗时
System.out.println(Thread.currentThread().getName()+"跑完了。"+new Date());
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//STEP 6
endGate.countDown();
}
}
}.start();
}
//模拟一些可能消耗时间的操作
TimeUnit.SECONDS.sleep(1);
long start=System.nanoTime();
//STEP 3
System.out.println("信号枪响起,biu biu biu!");
startGate.countDown();
//STEP 5
System.out.println("等待所有任务完成...");
endGate.await();//等待所有任务线程执行完毕
//STEP 7
System.out.println("所有任务执行完毕!"+new Date());
long end = System.nanoTime();
long deltaTime = end-start;
System.out.println("所有任务执行完耗时(S):"+deltaTime/1000_000_000);
}
}
执行结果↓:

3. CyclicBarrier测试代码
package com.example.conncurrency;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
/**
* 栅栏Test
*/
public class CyclicBarrierTest {
public static void main(String[] args) {
int count = 5;
//栅栏
//CyclicBarrier cyclicBarrier = new CyclicBarrier(count);//构造函数类型一,只有1个参数
final CyclicBarrier cyclicBarrier = new CyclicBarrier(count, new Runnable() {//构造函数类型二。第二个Runnable类型的参数表示到达汇合点await()后需要优先要执行的额外任务体,之后其他线程的await()之后的任务才会执行。
@Override
public void run() {
System.out.println("大家到齐了,先听领导讲几句...");
try {
System.out.println("......");
//模拟一些耗时操作
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
for (int i = 0; i < count; ++i) {
final int index = i;
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "出发了!还要一会到约定地点。" + new Date());
try {
TimeUnit.SECONDS.sleep(new Random(index).nextInt(5));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "到地方了,等待大家一起搞事情..." + new Date());
try {
cyclicBarrier.await();//当足够多的线程都到达这个位置,才会放行。 通过后,栅栏将被充值,可重复使用
} catch (InterruptedException e) {
e.printStackTrace();
return;
} catch (BrokenBarrierException e) {
e.printStackTrace();
return;
}
System.out.println(Thread.currentThread().getName() + ":大家都到了,我们一起去玩耍!" + new Date());
}
}, "老" + i).start();
}
}
}
执行结果↓:

4. Exchanger测试代码
package com.example.conncurrency;
import java.util.Date;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.Exchanger;
import java.util.concurrent.TimeUnit;
public class ExchangerTest {
public static void main(String[] args) {
final Exchanger<String> exchanger = new Exchanger<>();
final CyclicBarrier cyclicBarrier=new CyclicBarrier(2, new Runnable() {
@Override
public void run() {
System.out.println("================完成一次数据交换===================");
System.out.println(" ");
}
});
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
String msg = Thread.currentThread().getName()+"产生的消息。";
System.out.println(Thread.currentThread().getName() + "交换前的信息为:" + msg+" "+new Date());
try {
//两个线程在此将相互等待。在此反复汇合后通过(可重复使用)。用于两个线程的场景,若有多于两个线程调用同一个Exchanger实例的此方法,则配对是随机的
msg = exchanger.exchange(msg);
System.out.println(Thread.currentThread().getName() + "交换后的得到的信息为:" + msg+" "+new Date());
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
}, "线程1").start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
String msg = Thread.currentThread().getName()+"产生的消息。";
System.out.println(Thread.currentThread().getName() + "交换前的信息为:" + msg+" "+new Date());
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
msg = exchanger.exchange(msg);//两个线程在此将相互等待。
System.out.println(Thread.currentThread().getName() + "交换后的得到的信息为:" + msg+" "+new Date());
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
}, "线程2").start();
}
}
执行结果↓:

5. Phaser测试代码
// TODO
执行结果:
todo
616

被折叠的 条评论
为什么被折叠?



