1.3.4 并发工具类CountDownLatch/Semaphore/CyclicBarrier/FutureTask

CountDownLatch的2个用途:
1. 所有线程都到达相同的起跑线后,再一起开始跑(并非同时开始,而是队列中一个唤醒另一个)【此情况需到达起跑线后再调用await()等待其他线程】
2. 所有线程都到达终点(执行完)后,再一起庆祝 (并非同时开始,而是队列中一个唤醒另一个)【此情况需到达起终点后再调用await()等待其他线程】
package com.study.concurrent_utils;
import java.util.concurrent.CountDownLatch;
public class Test_CountDownLatch {
/*
* 没隔1s开启一个线程,共开启6个线程
* 若希望6个线程 同时 执行某一操作
* 可以用CountDownLatch实现
*/
public static void test01() throws InterruptedException {
CountDownLatch ctl = new CountDownLatch(6);
for (int i = 0; i < 6; i++) {
new Thread() {
@Override
public void run() {
ctl.countDown();
try {
ctl.await();
// 6个线程都启动执行到此处时,打印如下
System.out.println("here I am...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
Thread.sleep(1000L);
}
}
/*
* 开启6个线程,6个线程都执行完后,才执行某个操作
* 可以用CountDownLatch来实现
*/
public static void test02() throws InterruptedException {
JamesCountDownLatch ctl = new JamesCountDownLatch(6);
for (int i = 0; i < 6; i++) {
new Thread() {
@Override
public void run() {
System.out.println("after print...");
ctl.countDown();
}
}.start();
Thread.sleep(1000L);
}
ctl.await();
// 6条线程都执行完后同时打印这句话
System.out.println("main thread do something ...");
}
public static void main(String args[]) throws InterruptedException {
test02();
}
}
CountDownLatch实际应用
在zookeeper的master选举机制中,守护线程监听zk节点删除事件,一旦触发,CountDownLatch减1变成0,即触发线程继续递归调用选举逻辑
import java.util.concurrent.CountDownLatch;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.exception.ZkNodeExistsException; public class MasterElectionDemo { static class Server { private String cluster, name, address; private final String path, value; private String master; public Server(String cluster, String name, String address) {
super();
this.cluster = cluster;
this.name = name;
this.address = address;
path = "/" + this.cluster + "Master";
value = "name:" + name + " address:" + address; ZkClient client = new ZkClient("localhost:2181");
client.setZkSerializer(new MyZkSerializer()); new Thread(new Runnable() { @Override
public void run() {
electionMaster(client);
} }).start();
} public void electionMaster(ZkClient client) {
try {
client.createEphemeral(path, value);
master = client.readData(path);
System.out.println(value + "创建节点成功,成为Master");
} catch (ZkNodeExistsException e) {
master = client.readData(path);
System.out.println("Master为:" + master);
} // 为阻塞自己等待而用
CountDownLatch cdl = new CountDownLatch(1); // 注册watcher
IZkDataListener listener = new IZkDataListener() { @Override
public void handleDataDeleted(String dataPath) throws Exception {
System.out.println("-----监听到节点被删除");
cdl.countDown();
} @Override
public void handleDataChange(String dataPath, Object data) throws Exception { }
}; client.subscribeDataChanges(path, listener); // 让自己阻塞
if (client.exists(path)) {
try {
cdl.await();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
// 醒来后,取消watcher
client.unsubscribeDataChanges(path, listener);
// 递归调自己(下一次选举)
electionMaster(client); } } public static void main(String[] args) {
// 测试时,依次开启多个Server实例java进程,然后停止获取的master的节点,看谁抢到Master
// Server s = new Server("cluster1", "server1", "192.168.1.11:8991");
// Server s = new Server("cluster1", "server2", "192.168.1.11:8992");
Server s = new Server("cluster1", "server3", "192.168.1.11:8993");
// Server s = new Server("cluster1", "server4", "192.168.1.11:8994");
} }
手写CountDownLatch(基于AQS)
countDown()方法:释放共享锁,首先会尝试释放共享锁(其实际是做CAS操作将state减1,如果state减到了0,返回true),如果返回true,说明读锁已释放完,则将等待队列头部线程唤醒。
await()方法:获取共享锁,首先会尝试获取共享锁(其实际操作,获取并判断state值:return getState()==0 ? 1: -1;),若state不是0,即所有线程还没到齐,集体活动还不能开始,此时将其加入等待队列,并且开始自旋,不断判断自己是不是队列头部,即下一个开始跑的是不是自己,是的话就再次尝试获取共享锁,若失败就将自己挂起,若成功即从等待队列移除,并唤醒下一个要获取共享锁的线程。
package com.study.concurrent_utils;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
public class JamesCountDownLatch {
private Sync sync;
public JamesCountDownLatch(int count) {
sync = new Sync(count);
}
public void countDown() {
sync.releaseShared(1);
}
public void await() {
sync.acquireShared(1);
}
class Sync extends AbstractQueuedSynchronizer {
public Sync(int count) {
setState(count);
}
@Override
protected int tryAcquireShared(int arg) {
// 只有当state变为0时,加锁成功
return getState() == 0 ? 1 : -1;
}
/*
* countdown的方法
*/
@Override
protected boolean tryReleaseShared(int arg) {
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c - arg;
// 用CAS操作,讲count减一
if (compareAndSetState(c, nextc)) {
// 当state=0时,释放锁成功,返回true
return nextc == 0;
}
}
}
}
}

手写Semaphore(基于AQS)
package com.study.concurrent_utils;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
public class JamesSemaphore {
private Sync sync;
public JamesSemaphore(int state) {
sync = new Sync(state);
}
public void acquire() {
sync.acquireShared(1);
}
public void release() {
sync.releaseShared(1);
}
class Sync extends AbstractQueuedSynchronizer {
int state;
public Sync(int state) {
this.state = state;
}
@Override
protected int tryAcquireShared(int arg) {
for (;;) {
int available = getState();
int remaining = available - arg;
if (remaining < 0 || compareAndSetState(available, remaining))
return remaining;
}
}
@Override
protected boolean tryReleaseShared(int arg) {
for (;;) {
int current = getState();
int next = current + arg;
if (next < current) // overflow
throw new Error("Maximum permit count exceeded");
if (compareAndSetState(current, next))
return true;
}
}
}
}

package com.study.concurrent_utils;
import java.util.concurrent.CyclicBarrier;
public class TestCyclicBarrier {
public static void main(String[] args) throws InterruptedException {
CyclicBarrier cyclicBarrier = new CyclicBarrier(3, new Runnable() {
@Override
public void run() {
System.out.println(">>>>3个已满,走起<<<");
}
});
for (int i = 0; i < 30; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
cyclicBarrier.await();
System.out.println(Thread.currentThread() + ":start...");
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
Thread.sleep(1000L);
}
}
}
>>>>3个已满,走起<<<
Thread[Thread-2,5,main]:start...
Thread[Thread-0,5,main]:start...
Thread[Thread-1,5,main]:start...
>>>>3个已满,走起<<<
Thread[Thread-5,5,main]:start...
Thread[Thread-3,5,main]:start...
Thread[Thread-4,5,main]:start...
>>>>3个已满,走起<<<
Thread[Thread-8,5,main]:start...
Thread[Thread-6,5,main]:start...
Thread[Thread-7,5,main]:start...
手写CyclicBarrier(基于ReentrantLock)
ReentrantLock的Condition就是一个等待队列,ReentrantLock是一个可重入锁
package com.study.concurrent_utils; import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock; public class JamesCyclicBarrier { private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition(); // 记录当前这个批次有多少个
private int count = 0; // 记录批次的大小
private final int parties; // 分代
private Object generation = new Object(); public JamesCyclicBarrier(int parties) {
if (parties <= 0)
throw new IllegalArgumentException();
this.parties = parties;
} // 进入下一个分代
public void nextGeneration() {
condition.signalAll();
count = 0;
generation = new Object();
} public void await() {
// 实现排队,需要将线程放到等待队列
// 还需要将线程挂起
//
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 记录当前的generation,相当于记录当前批次的id
final Object g = generation; int index = ++count;
// 批次已经达到parties,
if (index == parties) {
// 进入下一个批次
nextGeneration();
return;
} // 若未达到批次,就进入等待
for (;;) {
try {
condition.await();
} catch (InterruptedException e) { }
if (g != generation) {
return;
}
} } finally {
lock.unlock();
}
}
}
Future/Runnable
package com.study.futuretask; import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.locks.LockSupport; public class Demo3_CallableTest {
public static void main(String args[]) throws InterruptedException, ExecutionException {
CallTask cTask = new CallTask();
JamesFutureTask<String> fTask = new JamesFutureTask<String>(cTask); // 执行第一次
Thread th = new Thread(fTask);
th.start(); System.out.println("begain to get...");
String result = fTask.get();
System.out.println(result); // 执行第二次,失败
Thread th1 = new Thread(fTask);
th1.start();
}
} class CallTask implements Callable<String> { @Override
public String call() throws Exception {
LockSupport.parkNanos(1000 * 1000 * 1000 * 5L);
System.out.println("done...");
return "James";
}
}
手写FutureTask
package com.study.futuretask; import java.util.concurrent.Callable;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport; public class JamesFutureTask<T> implements Runnable { // future只能执行一次
private volatile int state = NEW;
private static final int NEW = 0;
private static final int RUNNING = 1;
private static final int FINISED = 2; public JamesFutureTask(Callable<T> task) {
this.callable = task;
} // 程序执行的结果
private T result; // 要自行的task
Callable<T> callable; // 获取结果的线层等待队列
LinkedBlockingQueue<Thread> waiters = new LinkedBlockingQueue<>(100); // 执行当前FutureTask的线程,用CAS进行争抢
AtomicReference<Thread> runner = new AtomicReference<>(); @Override
public void run() {
// 判断当前对象的状态,如果是New就执行,如果
if (state != NEW || !runner.compareAndSet(null, Thread.currentThread()))
return;
state = RUNNING; try {
result = callable.call();
} catch (Exception e) {
e.printStackTrace();
} finally {
state = FINISED;
} // 方法执行完,唤醒所有线程
while (true) {
Thread waiter = waiters.poll();
if (waiter == null)
break;
LockSupport.unpark(waiter);
} } public T get() {
if (state != FINISED) {
waiters.offer(Thread.currentThread());
} while (state != FINISED) {
LockSupport.park();
} return result;
}
}
1.3.4 并发工具类CountDownLatch/Semaphore/CyclicBarrier/FutureTask的更多相关文章
- Java中的并发工具类(CountDownLatch、CyclicBarrier、Semaphore、Exchanger)
在JDK的并发包里提供了很多有意思的并发工具类.CountDownLatch.CyclicBarrier和Semaphore 工具类提供了一种并发流程控制的手段,Exchanger 工具类则提供了在线 ...
- 25.大白话说java并发工具类-CountDownLatch,CyclicBarrier,Semaphore,Exchanger
1. 倒计时器CountDownLatch 在多线程协作完成业务功能时,有时候需要等待其他多个线程完成任务之后,主线程才能继续往下执行业务功能,在这种的业务场景下,通常可以使用Thread类的join ...
- java多线程10:并发工具类CountDownLatch、CyclicBarrier和Semaphore
在JDK的并发包(java.util.concurrent下)中给开发者提供了几个非常有用的并发工具类,让用户不需要再去关心如何在并发场景下写出同时兼顾线程安全性与高效率的代码. 本文分别介绍Coun ...
- 多线程学习笔记六之并发工具类CountDownLatch和CyclicBarrier
目录 简介 CountDownLatch 示例 实现分析 CountDownLatch与Thread.join() CyclicBarrier 实现分析 CountDownLatch和CyclicBa ...
- JAVA并发工具类---------------(CountDownLatch和CyclicBarrier)
CountDownLatch是什么 CountDownLatch,英文翻译为倒计时锁存器,是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待. 闭锁可以延迟线程的进 ...
- Java 并发工具类 CountDownLatch、CyclicBarrier、Semaphore、Exchanger
本文部分摘自<Java 并发编程的艺术> CountDownLatch CountDownLatch 允许一个或多个线程等待其他线程完成操作.假设现有一个需求:我们需要解析一个 Excel ...
- Java中的4个并发工具类 CountDownLatch CyclicBarrier Semaphore Exchanger
在 java.util.concurrent 包中提供了 4 个有用的并发工具类 CountDownLatch 允许一个或多个线程等待其他线程完成操作,课题点 Thread 类的 join() 方法 ...
- Java并发工具类 - CountDownLatch
Java并发工具类 - CountDownLatch 1.简介 CountDownLatch是Java1.5之后引入的Java并发工具类,放在java.util.concurrent包下面 http: ...
- Java并发(十五):并发工具类——信号量Semaphore
先做总结: 1.Semaphore是什么? Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源. 把它比作是控制流量的红绿灯,比如XX马路要 ...
随机推荐
- vue中setInterval的清除
两种清除setInterval的方式: 方案一: data() { return { timer: null // 定时器名称 } }, mouted() { this.timer = (() =&g ...
- LVM问题-----Insufficient Free Extents for a Logical Volume
Linux LVM学习——Insufficient Free Extents for a Logical Volume 如下所示,在创建LV的时候,偶尔会遇到“Volume group "x ...
- JAVA基础知识|进程与线程
一.什么是进程?什么是线程? 操作系统可以同时支持多个程序的运行,而一个程序可以狭义的认为就是一个进程.在一个进程的内部,可能包含多个顺序执行流,而每个执行流就对应一个线程. 1.1.进程 进程:是计 ...
- 【SVN】彻底 svn 服务器上的 删除某一个文件或文件夹
参考: CSDN1:https://blog.csdn.net/u011729865/article/details/78764523 CSDN2:https://blog.csdn.net/wyyo ...
- kvm安装及简单使用
1 cat /etc/redhat-release CentOS release 6.4 (Final)2 egrep ‘vmx|svm’ /proc/cpuinfo3 yum -y ins ...
- app微信支付的集成步骤
1.引用地址 //微信支付 compile 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+' 2.注册 private IWXAPI api ...
- 打印Linq生成的SQL语句
var t1 = source.OrderBy<T>(orderby).Skip<T>(_skip).Take<T>(_take); var t2 = t1.ToO ...
- nginx服务报错解决
403禁止访问解决 . 重要:修改配置文件使用虚拟机,否则怎么配置都不生效,添加如下用户 [root@host---- html]# ll /etc/nginx/nginx.conf -rw-r--r ...
- SQLAlchemy如何筛选值为None的列?那么django呢
示例 from sqlalchemy import create_engine, MetaData, and_, or_, TIMESTAMP Plugin.query.filter(and_(Plu ...
- Visual Studio Code 调试 SpringBoot
Build Anything with Spring Boot:Spring Boot is the starting point for building all Spring-based appl ...