JUC--CountDownLatch介绍

一、CountDownLatch介绍

​ CountDownLatch是juc并发包下的一个同步工具类,用于协调多个线程之间同步的或者说线程之间的通信,告诉某一线程等待其他线程执行完后再执行,无法起到互斥作用;

​ 线程计数器,创建对象时可初始化线程计数值,每当执行完一个线程可调用对应的方法计数器减1,当计数器为0零被中断的线程开始运行。

用法:当需要多个线程并行结束后再执行最终线程,例如计算多个线程并行的运行效率,或者线程A计算公司支出,线程B计算公司盈利,则最后线程C等待线程A/B执行完毕后即可计算出公司利润。

​ 缺点:CountDownLatch是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当CountDownLatch使用完毕后,它不能再次被使用。

二、简单演示:

​ 一个线程计算公司支出费用;

​ 一个线程计算公司营业额;

​ 最后计算公司净利润;

package com.cjy.juc;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class CountDownLatchDemo {
        public static void main(String[] args) {
            Company company = new Company();
               //初始化计数线程,与实际执行线程等,不然可能造成await()的线程阻塞;
            CountDownLatch latch = new CountDownLatch(2);
            PayThread t1 = new PayThread(company, latch);
            ProfitThread t2 = new ProfitThread(company, latch);
            new Thread(t1).start();
            new Thread(t2).start();

            try {
                latch.await();//调用线程被挂起
            } catch (InterruptedException e) {
            }
            double pay = company.getPay();
            double profit = company.getProfit();
            System.out.println("2018年夏季支出费用:"+pay+"万元");
            System.out.println("2018年夏季营业额:"+profit+"万元");
            System.out.println("2018年夏季净利润:"+(profit-pay)+"万元");
        }
}
//公司
class Company{
    private double pay;
    private double profit;
    public double getPay() {
        return pay;
    }
    public void setPay(double pay) {
        this.pay = pay;
    }
    public double getProfit() {
        return profit;
    }
    public void setProfit(double profit) {
        this.profit = profit;
    }


}
//计算支出线程
class PayThread implements Runnable{
    private volatile Company cy;
    private CountDownLatch latch;
    PayThread(Company cy,CountDownLatch latch){
        this.cy=cy;
        this.latch=latch;
    }
    @Override
    public void run() {
        try{
            double pay = cy.getPay();
            for (int i = 0; i < 800; i++) {
                pay+=Math.random()*i;
            }
            cy.setPay(pay);
        }finally{
            latch.countDown();
        }
    }
}
//计算盈利线程
class ProfitThread implements Runnable{
    private volatile Company cy;
    private CountDownLatch latch;
    ProfitThread(Company cy,CountDownLatch latch){
        this.latch=latch;
        this.cy=cy;
    }
    @Override
    public void run() {
        try{
            double profit = cy.getProfit();
            for (int i = 0; i < 1000; i++) {
                profit+=Math.random()*i;
            }
            cy.setProfit(profit);
        }finally{
            latch.countDown();
        }
    }
}
三、CountDownLatch常用方法:
//构造函数,count与实际执行线程对应,如这里创建时count=100,那么就要有100个子线程来调用countDown()方法,不然被await()的线程又没有设置等待时间参数将不会执行一直处于阻塞状态
public CountDownLatch(int count) {
  if (count < 0) throw new IllegalArgumentException("count < 0");
  this.sync = new Sync(count);
}
//计算器减1,一般在每个线程执行结束后调用一次
public void countDown() {
  sync.releaseShared(1);
}
//调用线程处于阻塞状态,等待计数器为0时才会执行,这是一个重载函数; 
public void await() throws InterruptedException {
  sync.acquireSharedInterruptibly(1);
}
//设置等待时间,假如设置等待时间为5秒,则不等计数器为0时超过5秒后即会继续执行
public boolean await(long timeout, TimeUnit unit)
  throws InterruptedException {
  return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
//计数器当前值
public long getCount() {
  return sync.getCount();
}

借鉴与:https://blog.csdn.net/joenqc/article/details/76794356

    原文作者:JUC
    原文地址: https://blog.csdn.net/qq_35241080/article/details/82463323
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞