原创

java面试题-Semaphore、CountDownLatch 的实现原理是什么?

引言

在多线程编程中,Semaphore(信号量)和CountDownLatch(倒计时门栓)是两个常用的同步工具,用于协调线程的执行流程。本教程将深入浅析Semaphore和CountDownLatch的实现原理,通过详细的示例代码和解析,帮助初学者深入理解这两个工具的内部机制。

1. Semaphore(信号量)的实现原理

1.1 概念介绍

Semaphore通过new Semaphore(permits)来创建,其中permits表示同一时间可以执行多少个线程。通过acquire来获得许可,通过release来释放许可。在同一时间只允许permits个线程同时运行。

1.2 实现原理解析

  1. 调用new Semaphore(permits)时,内部创建了一个NonfairSync对象,permits表示信号量的初始值。
  2. 当调用acquire()申请许可时,实际上调用了NonfairSyncnonfairTryAcquireShared方法。
  3. 获取共享锁的过程是调用nonfairTryAcquireShared方法,将state减1,如果state小于0,则表示许可不足,申请许可失败,当前线程会构造成Waiter结点放入同步队列中。
  4. 如果state大于等于0,通过CAS(Compare and Swap)去更新state的值,如果CAS失败,则会一直循环尝试,直到成功。
  5. 如果CAS设置成功,表示持有锁成功。
  6. 如果CAS设置锁失败,将当前线程构造成Waiter结点放入同步队列中,线程处于等待状态。
  7. 当调用release后或发生线程中断时,等待的线程开始争抢锁。

1.3 示例代码

import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    private final Semaphore semaphore = new Semaphore(5);

    public void executeTask() {
        try {
            semaphore.acquire(); // 获取许可
            // 执行任务的逻辑
            // ...
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release(); // 释放许可
        }
    }
}

在上述代码中,通过acquire获取许可,执行任务的逻辑,然后通过release释放许可。

2. CountDownLatch的实现原理

2.1 概念介绍

CountDownLatch内部维护了一个计数器,通过countDown方法将计数器减1,当计数器为0时,所有阻塞的线程从await方法返回。

2.2 实现原理解析

CountDownLatch的原理主要涉及到计数器的减少和阻塞线程的唤醒。

  1. 每次调用countDown方法会将内部计数器减1。
  2. 如果计数器为0,唤醒所有阻塞在await上的线程。
  3. 阻塞的线程在await时,会检查计数器是否为0,如果不为0,线程将被挂起。
  4. 如果计数器为0,线程被唤醒,继续执行后续逻辑。

2.3 示例代码

import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
    private final CountDownLatch latch = new CountDownLatch(3);

    public void executeTask() {
        // 执行任务的逻辑
        // ...

        latch.countDown(); // 计数器减1
    }

    public void awaitCompletion() {
        try {
            latch.await(); // 阻塞等待计数器为0
            // 所有任务完成后的逻辑
            // ...
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在上述代码中,通过countDown方法将计数器减1,通过await方法阻塞等待计数器为0,从而实现线程协作的效果。

3. 总结

本教程深入浅析了Semaphore和CountDownLatch的实现原理,通过分析其内部机制和提供的API,帮助初学者更好地理解和应用这两个同步工具。通过示例代码演示,使读者能够清晰地了解在实际编程中如何使用Semaphore和CountDownLatch。

正文到此结束
本文目录