J.U.C之CountDownLatch
来源:互联网 发布:moedaze 优化 编辑:程序博客网 时间:2024/05/16 05:03
J.U.C之CountDownLatch
一、CountDownLatch介绍
CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程等待。
用给定的计数初始化CountDownLatch。由于调用了CountDown方法,所以在当计数达到0之前,await方法会一直阻塞。之后,会释放所有等待的线程,await的所有后续调用都将立即返回。
CountDownLatch经典的做法是两种:
1. 作为开关:
l 初始化计数器为1,作为一个主子线程的开关。
l 初始化计数器为n,主线程等待n个子线程完成任务后再执行后续的工作
2. 拆分子任务
将一个问题分成 N 个部分,用执行每个部分并让锁存器倒计数的 Runnable 来描述每个部分,然后将所有 Runnable 加入到 Executor 队列。当所有的子部分完成后,协调线程就能够通过 await。
二、实例
开关的使用:
package com.mylearn.thread;
import com.mylearn.util.DateUtil;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
/**
* Created by IntelliJ IDEA.
* User: yingkh
* Date: 12-12-20
* Time: 上午10:59
* CopyRight:360buy
* Descrption: CountDownLatch 类的使用
* To change this template use File | Settings | File Templates.
*/
public class CountDownLatchDemo {
public static void main(String args[]) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(2); //保证子线程完毕后主线程继续工作
CountDownLatch countDownLatchMain = new CountDownLatch(1); //保证子线程同时开始工作
Worker worker1 = new Worker("zhangsna", 5000, countDownLatch,countDownLatchMain);
Worker worker2 = new Worker("lisi", 8000, countDownLatch,countDownLatchMain);
worker1.start();
worker2.start();
doSth();
countDownLatchMain.countDown();//在 countDownLatchMain计数器减1之前,子线程是阻塞的
countDownLatch.await();//等待所有工人完成工作,主线程才能继续工作
doSthElse();
System.out.println("all work complete at" + DateUtil.date2String(new Date(), DateUtil.DATE_FORMAT_1));
}
private static void doSthElse() {
try {
System.out.println("主线程再休息一秒");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
private static void doSth() {
try {
System.out.println("主线程休息一秒");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
static class Worker extends Thread {
String workerName;
int workTime;
CountDownLatch countDownLatch;
CountDownLatch countDownLatchMain;
public Worker(String workerName, int workTime, CountDownLatch countDownLatch, CountDownLatch countDownLatchMain) {
this.workerName = workerName;
this.workTime = workTime;
this.countDownLatch = countDownLatch;
this.countDownLatchMain = countDownLatchMain;
}
public void run() {
try {
countDownLatchMain.await();
} catch (InterruptedException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
System.out.println("Worker " + workerName + " do work begin at" + DateUtil.date2String(new Date(), DateUtil.DATE_FORMAT_1));
doWork(); //工作
System.out.println("Worker " + workerName + " do work complete at" + DateUtil.date2String(new Date(), DateUtil.DATE_FORMAT_1));
countDownLatch.countDown(); //完成工作,计数器减1
}
private void doWork() {
try {
Thread.sleep(workTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
结果:
主线程休息一秒
Worker zhangsna do work begin at2013-11-10 08:53:06
Worker lisi do work begin at2013-11-10 08:53:06
Worker zhangsna do work complete at2013-11-10 08:53:11
Worker lisi do work complete at2013-11-10 08:53:14
主线程再休息一秒
all work complete at2013-11-10 08:53:15
第二种用法:
package com.mylearn.thread;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by IntelliJ IDEA.
* User: yingkh
* Date: 13-11-10
* Time: 上午8:56
* CopyRight:360buy
* Descrption:
* CountDownLatch的第二种使用,通过
* To change this template use File | Settings | File Templates.
*/
public class CountDownLatch2Demo {
public static void main(String args[]) {
int n=10;
CountDownLatch countDownLatch =new CountDownLatch(n);
ExecutorService executorService = Executors.newCachedThreadPool();
for(int i=0;i<n;i++) {
Woker woker =new Woker(i,countDownLatch);
executorService.submit(woker); //调用不同的worker工作
}
try {
countDownLatch.await();
System.out.println("end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
static class Woker implements Runnable{
int i;
CountDownLatch countDownLatch;
Woker(int i, CountDownLatch countDownLatch) {
this.i = i;
this.countDownLatch = countDownLatch;
}
public void run() {
dowWork(i); //根据参数调用做不同的事
countDownLatch.countDown();
}
private void dowWork(int i) { //模拟分页
int pageSize = 100;
int begin = i* 100;
int end = begin+99;
System.out.println("worker is running between ["+ begin +"] with [" + end+"].");
}
}
}
三、源码分析
Await:
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
acquireSharedInterruptibly:
public final void acquireSharedInterruptibly(int arg) throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
tryAcquireShared:
public int tryAcquireShared(int acquires) {
return getState() == 0? 1 : -1; //
}
countDownLatch的tryAcquireShared方法非常简单,只是判断计数是否为0;如果为0,线程不受影响,如果大于0,需要阻塞线程。doAcquireSharedInterruptibly是AQS公用的阻塞方法,在前几篇中分享过,此处略。
countDown:
public void countDown() {
sync.releaseShared(1);
}
releaseShared
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) { //返回true之后,唤醒阻塞队列
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
tryReleaseShared
public 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; //只有减为0时会返回true
}
}
}
countDown操作很简单,仅仅是更新计数器,通过CAS,减一;如果减为0的时候唤醒阻塞队列
- J.U.C之CountDownLatch
- “J.U.C”:CountDownlatch (r)
- 【死磕Java并发】-----J.U.C之并发工具类:CountDownLatch
- 浅析J.U.C的AQS(一):CountDownLatch
- 浅析J.U.C的AQS(一):CountDownLatch
- 【Java并发编程实战】—–“J.U.C”:CountDownlatch
- 【Java并发编程实战】—–“J.U.C”:CountDownlatch
- 【Java并发编程实战】-----“J.U.C”:CountDownlatch
- J.U.C之Future
- J.U.C之CopyOnWriteArrayList
- J.U.C之CyclicBarrier
- J.U.C之Semaphore
- J.U.C之Exchanger
- J.U.C之Lock
- J.U.C之Condition
- J.U.C之ConcurrentHashMap分析
- J.U.C之Atomic&CAS
- 压轴大戏:J.U.C之AQS
- linux 下 安装使用 cmake
- spring学习笔记——spring Hello world Web版
- Java中hashmap和hashtable的区别
- 一次.NET Web应用程序安装包的制作经历:Sql数据库安装的3种方式
- 参照大牛 结合自己的理解C++设计模式---单例模式( SingleTon Pattern)
- J.U.C之CountDownLatch
- C++类中的static数据成员,static成员函数
- 【U盘无法停止通用卷 装机吧教你解决】
- 无名管道的C++封装
- 使用vspd虚拟com,打开失败
- 函数调用的栈与帧
- Cocos2D-XNA入门篇
- 图形绘制刷新闪烁问题
- ubuntu上 QT 连接各种数据库报错解决(QSqlDatabase: * driver not loaded )