countDownLatch使用、原理、面试题

CountDownLatch是一个同步工具类,常用于多线程的协调,使其等待其他线程完成操作。它以计数器为基础,初始化为线程数量,每个线程完成任务后计数器减1,当计数器归零时,所有等待的线程可以继续执行。应用场景包括服务可用性检测、协同作业、模拟高并发和ZooKeeper连接。与CyclicBarrier不同,CountDownLatch计数器无法重置,而CyclicBarrier可以重置并支持多个线程相互等待。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用:

场景1:等待driver完成后再执行其他线程(服务可用性检测)。

package mianshi.countdownlatch;

import java.util.Random;
import java.util.concurrent.CountDownLatch;

public class Driver {
	public static void main(String[] args) throws Exception {
		CountDownLatch startSignal = new CountDownLatch(1);
		CountDownLatch doneSignal = new CountDownLatch(10);
		for (int i = 0; i < 10; i++) {
			new Thread(new Worker(startSignal, doneSignal)).start();
		}
		doSomethingElse();//开启驱动
		startSignal.countDown();
		doneSignal.await();//等待所有线程完成
		doOtherthingElse();//完成后做其他事
		System.out.println(doneSignal.getCount());//0
	}

	static void doSomethingElse() {
		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("driver is ok");
	}
	static void doOtherthingElse() {
		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("things done");
	}
}

class Worker implements Runnable {
	private final CountDownLatch startSignal;
	private final CountDownLatch doneSignal;

	Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
		this.startSignal = startSignal;
		this.doneSignal = doneSignal;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
			startSignal.await();
			doWork();
			doneSignal.countDown();
		} catch (Exception e) {
		}
	}

	void doWork() {
		try {
			Thread.sleep((int)(Math.random()*10000));
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName());
	}

}

场景2:协同作业,等待作业完成。

package mianshi.countdownlatch;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Driver2 { // ...
	public static void main(String[] args) throws InterruptedException {
		CountDownLatch doneSignal = new CountDownLatch(10);
		ExecutorService e = Executors.newFixedThreadPool(10);

		for (int i = 0; i < 10; ++i) // create and start threads
			e.execute(new WorkerRunnable(doneSignal, i));
		doneSignal.await(); // wait for all to finish
		System.out.println(doneSignal.getCount());
		e.shutdown();
	}
}

class WorkerRunnable implements Runnable {
	private final CountDownLatch doneSignal;
	private final int i;

	WorkerRunnable(CountDownLatch doneSignal, int i) {
		this.doneSignal = doneSignal;
		this.i = i;
	}

	public void run() {
		doWork(i);
		doneSignal.countDown();
	}

	void doWork(int i) {
		System.out.println(i);
	}
}

 

场景3:实现最大并行性,模拟高并发

 

场景4:获取zook实例的时候,等待连接完成

	public static ZooKeeper getInstance(Watcher watcher) {
		ZooKeeper zk = null;
		try {
			CountDownLatch connectedSemaphore = new CountDownLatch(1);
			boolean needWait = false;
			if (watcher == null) {
				needWait = true;
				watcher = new Watcher() {
					public void process(WatchedEvent event) {
						if (KeeperState.SyncConnected == event.getState()) {
							connectedSemaphore.countDown();
						}
					}
				};
			}
			zk = new ZooKeeper(connectStr, sessionTimeout, watcher);
			if (needWait) {
				try {
					connectedSemaphore.await(10, TimeUnit.SECONDS);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

		} catch (IOException e) {
			LOGGER.error(e.getMessage(), e);
		}
		createChroot();
		return zk;
	}

 

 

CyclicBarrier例子:

中国式过马路,5人凑够数,就过,但是司机必须等到全部过去后才能过。

package mianshi.countdownlatch;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierTest {
	public static void main(String args[]) throws Exception {
        List<Person> list = new ArrayList<>();
        CyclicBarrier barrier = new CyclicBarrier(5);
        CountDownLatch latch = new CountDownLatch(10);
        TrafficLight light = new TrafficLight(barrier, latch);
        for (int i = 1; i <= 10; i++) {
            list.add(new Person(light));
        }
        Driver3 driver = new Driver3(light);
        new Thread(driver).start();
        Thread t = null;
        for (Person p : list) {
            p.setName("p" + (list.indexOf(p) + 1));
            t = new Thread(p);
            t.start();
            Thread.sleep(500);// 每过500ms来一个人
        }

    }
}


class Person implements Runnable {

    private TrafficLight light;
    private String name;

    public Person(TrafficLight light) {
        this.light = light;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println(name + "等红灯中.....");
        light.peopleWaitRedLight();
        System.out.println(name + "过马路....哒哒哒...");

    }
}

class Driver3 implements Runnable {
    private TrafficLight light;

    public Driver3(TrafficLight light) {
        this.light = light;
    }

    @Override
    public void run() {
        System.out.println("司机等红灯中...烦烦烦...");
        light.driverWaitRedLight();
        System.out.println("司机过马路喽...嘟嘟嘟...");
    }
}

class TrafficLight {
    private CyclicBarrier barrier;
    private CountDownLatch latch;

    public TrafficLight(CyclicBarrier barrier, CountDownLatch latch) {
        this.barrier = barrier;
        this.latch = latch;
    }

    public void driverWaitRedLight() {
        try {

            latch.await();
            Thread.sleep(1);// 让人完全走过去
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void peopleWaitRedLight() {
        try {
            this.barrier.await();
            System.out.println("凑够数了,大家一起闯红灯了.");
        } catch (InterruptedException | BrokenBarrierException e) {
            e.printStackTrace();
        } finally {
            if (latch != null) {
                latch.countDown();
            }
        }
    }

}
 

面试题: 

  • 解释一下CountDownLatch概念? 

     CountDownLatch是在jdk1.5引入的,在java.util.concurrent包下,允许一个或多个线程等待直到其他线程完成操作。

    CountDownLatch通过计数器来实现,初始值为线程的数量,每执行完一个线程 计数器减1,直到变成0,调用await方法的

      线程才能继续执行。

  • 给出一些CountDownLatch使用的例子? 

     1、核心服务检测

     2、模拟高并发

     3、zook连接

  •  CountDownLatch 类中主要的方法?

     await 当前线程等待直到计数器为0

    countDown 计数器减1

  • 说说 CountDownLatch、CyclicBarrier 原理和区别

   原理:

CountDownLatch:https://www.jianshu.com/p/7c7a5df5bda6

线程调用CountDownLatch await方法直到计数器减为0.

主要通过计数器,在调用CountDownLatch wait方法等时候,计数器减一,

CyclicBarrier:

再CyclicBarrier内部定义了一个Lock对象,每当一个线程调用await方法的时候,计数器减1,同时判断计数器是否为0,为0执行runable方法,重置栅栏,并唤醒所有在lock队列里面等待的线程,否则进入lock的等待队列。

  区别:  

    CyclicBarrier强调的是n个线程相互等待,直到完成再执行任务,计数器可以重置,复用,所以叫循环栅栏。

    CountDownLatch允许一个或多个线程等待直到其他线程完成操作  ,只能使用一次。

     参考裁判的例子:https://aaron-han.iteye.com/blog/1591755

参考:http://www.importnew.com/15731.html

           jdk源码

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值