并发-CountDownLatch、 CyclicBarrier、Semaphore
CountDownLatch
1.测试案例
package cn.zwc.demo;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
*
* @author zwc
* @date 2018年12月4日 下午7:53:24
*/
public class CountDownLatchDemo01 {
public static void main(String[] args) {
final CountDownLatch latch = new CountDownLatch(4);// 创建框架
for(int i = 0; i < 4; i++){
Thread threa = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"\t正在执行中!");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"\t执行完毕!");
latch.countDown(); // 框架计数器-1
}
},"task"+i);
threa.start();
}
System.out.println("4个线程正在执行");
// 唤醒等待
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main Thread.......");
}
}
执行结果
4个线程正在执行
task2 正在执行中!
task1 正在执行中!
task3 正在执行中!
task0 正在执行中!
task1 执行完毕!
task3 执行完毕!
task2 执行完毕!
task0 执行完毕!
main Thread.......
如果latch.await();
注释掉这一段的话,执行结果是
从以上的结果分析,latch.await();
只有等所有的线程执行完毕,才会执行其他的线程(main线程)
如果没有的话,主线程可能先于多线程执行完毕
2.源码解读
- 构造函数
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
- 执行计数
// CountDownLatch中的
public void countDown() {
sync.releaseShared(1);
}
调用的 releaseShared 是 AbstractQueuedSynchronizer.中的
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
tryReleaseShared 是 CountDownLatch中的内部类 Sync 中
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
doReleaseShared 是 AbstractQueuedSynchronizer的方法
private void doReleaseShared() {
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}
CyclicBarrier
1.测试案例
package cn.zwc.demo;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierTest {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(5);
for (int i = 0; i < 5; i++) {
Write write = new Write(cyclicBarrier);
write.start();
}
System.out.println("主线程执行完毕");
}
static class Write extends Thread {
private CyclicBarrier cyclicBarrier;
public Write(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
System.out.println("线程" + Thread.currentThread().getName() + ",正在写入数据");
try {
Thread.sleep(3000);
} catch (Exception e) {
}
System.out.println("线程" + Thread.currentThread().getName() + ",写入数据成功.....");
try {
cyclicBarrier.await();
} catch (Exception e) {
}
System.out.println("所有线程执行完毕..........");
}
}
}
执行结果:
主线程执行完毕
线程Thread-3,正在写入数据
线程Thread-0,正在写入数据
线程Thread-2,正在写入数据
线程Thread-1,正在写入数据
线程Thread-4,正在写入数据
线程Thread-0,写入数据成功.....
线程Thread-3,写入数据成功.....
线程Thread-2,写入数据成功.....
线程Thread-4,写入数据成功.....
线程Thread-1,写入数据成功.....
所有线程执行完毕..........
所有线程执行完毕..........
所有线程执行完毕..........
所有线程执行完毕..........
所有线程执行完毕..........
只有等待所有线程执行完成,才能执行之后的主线程
2.源码阅读
//
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen;
}
}
/**
* Main barrier code, covering the various policies.
*/
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
final ReentrantLock lock = this.lock;
// 加锁
lock.lock();
try {
final Generation g = generation;
// 判断当前线程是否是broken
if (g.broken)
throw new BrokenBarrierException();
// 判断当前线程是否被中断,如果被中断,调用 trip.signalAll();将会唤醒所有等待的线程
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
}
int index = --count;
if (index == 0) { // tripped
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
// loop until tripped, broken, interrupted, or timed out
for (;;) {
try {
if (!timed)
trip.await();
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
if (g == generation && ! g.broken) {
breakBarrier();
throw ie;
} else {
// We're about to finish waiting even if we had not
// been interrupted, so this interrupt is deemed to
// "belong" to subsequent execution.
Thread.currentThread().interrupt();
}
}
if (g.broken)
throw new BrokenBarrierException();
if (g != generation)
return index;
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
// 释放锁
lock.unlock();
}
}
Semaphore
1.测试案例
Semaphore 顾名思义,表示的是信号量,以下案例表示的是5个资源,同时只能2个竞争资源
package cn.zwc.demo;
import java.util.Random;
import java.util.concurrent.Semaphore;
/**
* 10个人抢三个资源的问题
* @author zwc
* @date 2018年8月2日 下午4:17:53
*/
public class SemaphoreTest {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(2);
for(int i = 1; i <= 5; i++){
Parent parent = new Parent("第"+ i +"个人", semaphore);
new Thread(parent).start();
}
}
static class Parent implements Runnable{
private String name;
private Semaphore wc;
public Parent(String name,Semaphore wc) {
this.name = name;
this.wc = wc;
}
@Override
public void run() {
try{
// int availablePermits = wc.availablePermits();
// 申请茅坑,如果资源到达三次,就等待
// if(availablePermits > 0){
// System.out.println(name+"天助我也,居然有座位");
// } else {
// System.out.println(name+"哎呀~,为啥没有座位了呢?");
// }
wc.acquire();
System.out.println(name+"我可以准备吃饭了。。。");
Thread.sleep(new Random().nextInt(1000));
System.out.println(name + "我吃完了呀");
wc.release();
System.out.println(name + "------释放了锁");
}catch(Exception e){
}
}
}
}
2.结果显示:
第1个人我可以准备吃饭了。。。
第2个人我可以准备吃饭了。。。
第1个人我吃完了呀
第1个人------释放了锁
第3个人我可以准备吃饭了。。。
第3个人我吃完了呀
第3个人------释放了锁
第5个人我可以准备吃饭了。。。
第2个人我吃完了呀
第2个人------释放了锁
第4个人我可以准备吃饭了。。。
第4个人我吃完了呀
第4个人------释放了锁
第5个人我吃完了呀
第5个人------释放了锁