Java程序有的时候在主线程中会创建多个线程去执行任务,然后在主线程执行完毕之前,把所有线程的任务进行汇总,以前可以用线程的join方法,但是这个方法不够灵活,我们可以使用CountDownLatch类,实现更优雅,而且使用线程池的话,可没有办法调用线程的join方法的呀!

一.简单使用CountDownLatch

  直接使用线程:

package com.example.demo.study;

import java.util.concurrent.CountDownLatch;

public class Study0215 {
//这里相当于新建一个初始值为2的计数器
private static volatile CountDownLatch countDownLatch = new CountDownLatch(2); public static void main(String[] args) throws InterruptedException { new Thread(()->{
try {
Thread.sleep(1000);
System.out.println("线程一执行完毕");
} catch (Exception e) { }finally {
//每调用这个方法计数器减一
countDownLatch.countDown();
} }).start(); new Thread(()->{
try {
Thread.sleep(1000);
System.out.println("线程二执行完毕");
} catch (Exception e) { }finally {
countDownLatch.countDown();
} }).start(); System.out.println("两个线程已经全部启动");
//只要调用了这个方法之后,主线程会阻塞,直到计数器countDownLatch变成0就会返回
countDownLatch.await();
System.out.println("执行完毕"); } }

  实际中尽量少直接操作线程,而是使用线程池:

package com.example.demo.study;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class Study0215 {
// 这里相当于新建一个初始值为2的计数器
private static volatile CountDownLatch countDownLatch = new CountDownLatch(2); public static void main(String[] args) throws InterruptedException {
//创建线程池
ExecutorService pool = Executors.newFixedThreadPool(2);
//将任务一丢进线程池
pool.submit(() -> {
try {
Thread.sleep(1000);
System.out.println("线程一执行完毕");
} catch (Exception e) { } finally {
// 每调用这个方法计数器减一
countDownLatch.countDown();
}
});
//任务二丢进线程池
pool.submit(() -> {
try {
Thread.sleep(1000);
System.out.println("线程二执行完毕");
} catch (Exception e) { } finally {
countDownLatch.countDown();
}
}); System.out.println("两个线程已经全部启动");
// 只要调用了这个方法之后,主线程会阻塞,直到计数器countDownLatch变成0就会返回
countDownLatch.await();
System.out.println("执行完毕"); } }

二.await方法

  看下面的图,可以知道这个CountDownLatch类内部有个工具类Sync实现了AQS,然后CountDownLatch中的方法都是调用工具类Sync去操作的,emmm....跟前面说过的ReentrantLock类结构是一样的;

  我们看看CountDownLatch构造器传递的数其实就是设置AQS中state的值:

//实际上调用把值传递给了Sync,也就是设置了AQS中的state
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
Sync(int count) {
setState(count);
}

 

  我们再看看await方法:

//当前线程调用了await方法之后,当前线程就会给阻塞,直到以下两种情况:
//1.其他线程调用了countDown方法将计数器减到0之后,该线程就返回了;
//2.其他线程调用了当前的线程的中断方法,当前线程抛出异常InterruptedException
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
} public final void acquireSharedInterruptibly(int arg) throws InterruptedException {
//当前线程被中断就抛出异常
if (Thread.interrupted())
throw new InterruptedException();
//查看计数器中的值是不是0,不过不是0,就进入AQS等待队列等待;
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
} protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}

三.countDown方法

public void countDown() {
sync.releaseShared(1);
} public final boolean releaseShared(int arg) {
//tryReleaseShared方法返回false,说明当前计数器的值减一成功
//返回true,说明计数器的值此时为0,那就要唤醒因为调用了CountDownLatch而阻塞的线程
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
} protected boolean tryReleaseShared(int releases) {
//一个无限循环
for (;;) {
//获取state的值
int c = getState();
//如果state为0,返回false
if (c == 0)
return false;
//否则就把state减一然后用CAS更新到state
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}

四.getState方法

  这个方法获取计数器的值,其实就是获取AQS中的state的值;

int getCount() {
return getState();
}
protected final int getState() {
return state;
}

  其实CountDownLatch比较容易,功能和Thread的join方法一样,只不过更灵活,基于AQS实现,在初始化的时候设置state的值,当线程调用CountDownLatch的await方法的时候,当前线程就会被丢到AQS的阻塞队列挂起;然后当其他线程调用了countDown方法,其实就是将state减一,当state等于0的时候,就会唤醒所有因为调用await方法而阻塞的线程;

线程同步器CountDownLatch的更多相关文章

  1. Semaphore控制同时访问的线程个数countdownlatch等待多个线程执行完本身线程再执行

    Semaphore控制同时访问的线程个数countdownlatch等待多个线程执行完本身线程再执行 Semaphore控制同时访问的线程个数countdownlatch等待多个线程执行完本身线程再执 ...

  2. 线程:CountDownLatch同步工具

    一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待. 类似计数器,当计数器的值为0时,继续往下执行. package ch03; import java.util.R ...

  3. Java多线程-两种常用的线程计数器CountDownLatch和循环屏障CyclicBarrier

    Java多线程编程-(1)-线程安全和锁Synchronized概念 Java多线程编程-(2)-可重入锁以及Synchronized的其他基本特性 Java多线程编程-(3)-从一个错误的双重校验锁 ...

  4. 线程等待——CountDownLatch使用

    告警性能优化过程中,遇到如下问题:1. 在数据库计算几十万个实体的KPI值的方差:2. 计算结果进行表格化处理. 这里KPI包含多个Counter的数据库函数运算(比如Decode,AVG等函数),方 ...

  5. 10.线程通信CountDownLatch

    CountDownLatch 1.一个同步的辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个.多个线程去一直等待,用给定的计数.初始化“CountDownLatch”. 由于调用 count ...

  6. 线程协作-CountDownLatch

    CountDownLatch允许一个或多个线程等待其他线程完成操作.

  7. Java线程:CountDownLatch 与Thread 的 join()

    需求: 主程序中需要等待所有子线程完成后 再继续任务 两种实现方式: 一种使用join() 方法:当在当前线程中调用某个线程 thread 的 join() 方法时,当前线程就会阻塞,直到thread ...

  8. 11.线程通信CountDownLatch

    package demo2; import java.util.concurrent.CountDownLatch; /** * Created by liudan on 2017/7/27. */ ...

  9. 线程同步-CountDownLatch

    应用场景: 有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以继续往下执行. 假如我们这个想要继续往下执行的任务调用一个CountDownLatch对象的await()方法,其他的任务执行 ...

随机推荐

  1. ISE post-place&route仿真准备

    ISE post-place&route仿真准备 使用目的:post-place&route仿真是综合后考虑门延时而进行的仿真.因为考虑到各个门的延时,所以可以发现行为仿真(behav ...

  2. 关于Dijk采访的一些感想

    有效的程序员不应该浪费很多时间用于程序调试,他们应该一开始就不要把故障引入! 反复,一遍又一遍的尝试,真的会让人心烦,对于有的问题解决不了,其实有很多原因,写出来的程序其实是非常考验人的细节处理能力的 ...

  3. 02-React基础语法(2)

    一.条件渲染 语法:使用原生 js 的 if 或者 三元表达式 判断   例子:判断用户是否登录,提示:已登录.未登录 (User组件) <script type="text/babe ...

  4. 剑指offer-面试题31-栈的压入弹出序列-栈

    #include<iostream> #include<string.h> #include<algorithm> #include<cmath> #i ...

  5. beego控制器介绍

    控制器介绍 提示:在 v1.6 中,此文档所涉及的 API 有重大变更,this.ServeJson() 更改为 this.ServeJSON(),this.TplNames 更改为 this.Tpl ...

  6. 敌兵布阵 HDU - 1166 板子题

    #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> ...

  7. Win10如何设置休眠选项(关于睡眠、休眠、快速启动这几个伪关机功能如何设置更适合笔记本电脑?)

    · Win10如何设置休眠选项(关于睡眠.休眠.快速启动这几个伪关机功能如何设置更适合笔记本电脑?) 应用场景 升级正式版win10以后,发现竟然没有休眠选项,从电源管理器里面也没有找到,有时候有些重 ...

  8. Grammar Framework 1

    Word is cheap, show me the grammar. Doc requirements:TODO 1. English doc 2. Mark the importance 语法框架 ...

  9. java类及实例初始化顺序

    1.静态变量.静态代码块初始化顺序级别一致,谁在前,就先初始化谁.从上而下初始化(只在类加载时,初始化一次) 2.非静态变量.非静态代码块初始化顺序级别一致,谁在前,就先初始化谁.从上而下初始化(只要 ...

  10. MySQL的聚合函数

    MySQL的聚合函数 网站:https://www.runoob.com/mysql/mysql-functions.html 函数名 功能描述 count() 计数 sum() 求和 avg() 平 ...