CountDownLatch
允许一个或者多个线程等待其他线程完成操作。
理解 CountDownLatch 构造函数中传 int N,需要执行countDown() N次后 await()方法组织的才能继续执行。
底部使用了乐观锁 compareAndSet(CAS)
贴代码:
package com.yhw.concurrenttest.utils;
import java.util.LinkedList;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
public class CountDownLatchTest {
public static void main(String[] args) {
/**
* demo需求
* 银行每个月进行月末查账 现在12个人 进行月末查账每个人的任务0-9个左右 每个任务的时间3000s左右
* 现在就 每个人插完账后 进行封账。
* 并发 12个人 12个线程同时处理
*/
CountDownLatch countDownLatch = new CountDownLatch(12);
LinkedList<Thread> linkedList = new LinkedList<Thread>();
for (int i = 1; i < 13; i++) {
Thread th= new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("进入线程"+Thread.currentThread().getName());
try {
Thread.sleep((long) (Math.random()*10*(3000*Math.random())));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.err.println(Thread.currentThread().getName()+"线程执行完成");
countDownLatch.countDown();
}
},"thread."+i);
linkedList.add(th);
}
Thread thall = new Thread(new Runnable() {
@Override
public void run() {
System.err.println("进入总线程等待");
try {
countDownLatch.await();
System.err.println("总线程执行完成");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"thall");
System.err.println("主函数。。。。。。。。。。。");
try {
Thread.sleep(2000);
thall.start();
for (int i = 0; i < linkedList.size(); i++) {
linkedList.get(i).start();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
CountDownLatch的构造函数接受一个int类型的参数作为计数器,如果想等待N个点这里就传入N
当我们调用CountDownLatch的countDown方法时,N就会减掉1,CountDownLatch的await()方法会阻塞当前的线程,直到N变成零。由于countDown方法可以用到任何地方。所以这里所得N个点就是N个线程,也可以是一个线程的N个步骤。
计数器N 必须大于0
CyclicBarrier 同步屏障
可以循环(Cyclic)使用的屏障(Barrier)。他要做的事情是,让一组线程到达一个屏障(也可以叫同步点)是被阻塞,直到最后一个线程到达屏障是,屏障才会开门,所以被拦截的线程才会继续运行。
cyclicBarrier默认的构造方法CyclicBarrier(int parties), 其参数表示屏障拦截线程输了,每个线程调用的await()方法告诉CyclicBarrier 我已经到达了屏障,然后单签的线程就被阻塞 知道最后一线程调用await 方法正好是构造函数中的参数,那么就结束线程,否则线程一直就会在阻塞状态。
普通构造函数
package com.yhw.concurrenttest.utils;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class UseCyclicBarrier {
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(3);
Thread th1 = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
System.err.println("进入线程"+Thread.currentThread().getName());
try {
barrier.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
},"th1");
Thread th2 = new Thread(new Runnable() {
@Override
public void run() {
System.err.println("进入线程"+Thread.currentThread().getName());
// TODO Auto-generated method stub
try {
barrier.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
},"th2");
th1.start();
th2.start();
System.err.println("主进程");
}
}
程序运行结果:
CycliBarrier(int parties,Runnale barrier-action)构造函数
用于线程到达屏障时候,优先执行barrieraction,方便处理更复杂的业务场景。
package com.yhw.concurrenttest.utils;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class UseCyclicBarrier2 {
public static void main(String[] args) {
CyclicBarrier cb = new CyclicBarrier(3,new B());
System.err.println("main*********************");
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
System.err.println(Thread.currentThread().getName()+"*************run");
try {
cb.await();
// TODO Auto-generated method stub
System.err.println(Thread.currentThread().getName()+"end*************run");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
System.err.println("end***************main");
}
static class B implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
System.err.println("B*******************run");
}
}
}
程序运行结果:
银行流水例子
package com.yhw.concurrenttest.utils;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
/**
* 处理银行流水类
* @author 71076
*
*/
public class UseCyclicBarrierTest implements Runnable {
private CyclicBarrier cyclicBarrier = new CyclicBarrier(4,this);
private Executor executor = Executors.newFixedThreadPool(4);
ConcurrentHashMap<String, Integer> sheetBankWaterCount = new ConcurrentHashMap<>();
private void count() {
System.err.println("count*********************");
for (int i = 0; i < 4; i++) {
executor.execute(new Runnable() {
@Override
public void run() {
System.err.println(Thread.currentThread().getName()+"******************Thread run");
sheetBankWaterCount.put(Thread.currentThread().getName(), 1);
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
});
}
}
@Override
public void run() {
// TODO Auto-generated method stub
System.err.println("run*******************");
int result = 0;
for(Entry<String, Integer> sheet: sheetBankWaterCount.entrySet()){
result+=sheet.getValue();
}
sheetBankWaterCount.put("result",result);
System.err.println(result);
}
public static void main(String[] args) {
UseCyclicBarrierTest barrierTest = new UseCyclicBarrierTest();
barrierTest.count();
}
}
、
比较CyclicBarrier和CountDownLatch区别
CountDownLatch的计数器智能使用一次,而CyclicBarrier的计数器可以使用reset()方法重置、所以CyclicBarrier能处理更为复杂的业务场景。例如,如果计算机发生错误,可以通过重置计数器,并让线程重启一次。