logo 范 · 拾光录
网址收集 关于作者 Github Gitee
杂文随笔4
Hexo博客:基础使用Hexo博客:Next主题Hexo博客:Next进阶使用Hexo博客:Next高级配置
前端编程3
前端基础知识16
UniApp15
Vue框架19
Java编程7
Java基础知识14
SpringBoot31
SpringMVC14
MyBatis8
SpringCloud15
RocketMQ1
MyCat1
数据库4
MySQL6
Redis7
MongoDB10
H21
Java技术栈4
知识整理分布式锁的实现方案MySQL事务MySQL的锁
软件工具箱14
IDEAGitMavenGradleNginx安装Nginx配置JMeter压测OllamaPicGoRustFSVSCodeDockerObsidianObs录制
Linux知识11
树莓派安装及使用ArchLinux:常用软件ArchLinux:基础系统安装ArchLinux:深度优化ArchLInux:图形化界面安装ArchLinux:Nirifrp内网穿透Jar启动脚本Linux常用命令VirtualBox安装CentOSVirtualBox安装Ubuntu
Python编程6
Python基础知识Python语法yolo目标检测OpenCV的使用及树莓派平台condauv
创意设计2
Blender:入门知识UI设计基础知识
AI相关9
Claude CodeHermes AgentOpenAI基本使用OpenAI工具调用OpenAI记忆管理OpenAI推理执行OpenAI开发框架Langchainllama.cpp

CopyOnWriteArrayList

JUC下的一个集合,线程安全,写时复制,当往一个容器中添加元素时,先对容器进行复制,添加到复制的容器中,再将原容器的引用指向新容器

CountDownLatch

是JUC(java.util.concurrent)包中的一个同步工具类,可以把它理解成一个倒计数门闩。它让一个或多个线程在门闩前等待,直到其他线程完成一系列操作,把计数器减到0,这个才会打开,等待的线程才能继续执行

CountDownLatch是处理线程协作的得力工具,尤其适合分而治之的任务场景,能有效简化多线程之间的协调逻辑

主要特点

两大核心方法

常见应用场景

主线程等待多个子任务完成:这是最常见的用法。主线程调用await(),然后启动多个子线程去执行任务,每个子线程执行完毕后调用countDown()。当所有子任务都完成,主线程才继续往下走

// 例子:主线程等待所有子线程完成任务
CountDownLatch doneSignal = new CountDownLatch(N);
ExecutorService e = Executors.newFixedThreadPool(N);
for (int i = 0; i < N; ++i) {
    e.execute(() -> {
        doWork(); // 执行子任务
        doneSignal.countDown(); // 完成,计数减1
    });
}
doneSignal.await(); // 主线程等待
System.out.println("所有任务完成");

多个线程同时开始执行:实现“统一发令,同时起跑”的效果。初始化一个计数器为1的CountDownLatch,所有工作线程先调用await()等待,主线程在准备好后调用countDown(),所有等待的线程就会同时被唤醒执行

CountDownLatch startSignal = new CountDownLatch(1);
for (int i = 0; i < 5; i++) {
    new Thread(() -> {
        startSignal.await(); // 等待发令枪
        doWork(); // 同时开始执行
    }).start();
}
// 主线程做准备工作...
startSignal.countDown(); // 发令,所有线程启动

最大并行性:利用两个CountDownLatch可以协调一组工作线程,第一个信号控制“同时开始”,第二个信号控制“一起结束”,这在压力测试中很常见

CyclicBarrier

CyclicBarrier(循环栅栏)和CountDownLatch很像,但它的核心概念是可循环使用的屏障

核心特点

常见应用场景

代码示例:3人斗地主准备

import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierDemo {
    public static void main(String[] args) {
        // 3个玩家准备,人齐后由最后一个到达的玩家执行“发牌”动作
        CyclicBarrier barrier = new CyclicBarrier(3, () -> {
            System.out.println("人都到齐了,开始发牌!");
        });

        // 模拟3个玩家线程
        for (int i = 1; i <= 3; i++) {
            final int playerId = i;
            new Thread(() -> {
                try {
                    System.out.println("玩家" + playerId + " 已进入房间,等待其他人...");
                    barrier.await(); // 等待其他玩家
                    System.out.println("玩家" + playerId + " 开始打牌了!");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

输出结果(每次运行顺序可能不同,但逻辑一致):

玩家1 已进入房间,等待其他人...
玩家2 已进入房间,等待其他人...
玩家3 已进入房间,等待其他人...
人都到齐了,开始发牌!
玩家3 开始打牌了!
玩家1 开始打牌了!
玩家2 开始打牌了!

进阶提示:常见陷阱

Semaphore

Semaphore(信号量)是JUC包中用于流量控制的同步工具,你可以把它想象成一个限流器

核心概念

Semaphore能确保最多只有N个线程可以同时访问某个资源或执行某段代码

常见应用场景

代码示例:限流器

下面模拟一个简单的限流场景,限制同时只有最多 3 个线程能执行打印任务:

import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadLocalRandom;

public class SemaphoreDemo {
    // 最多允许 3 个线程同时执行
    private static final Semaphore semaphore = new Semaphore(3);

    public static void main(String[] args) {
        // 模拟 10 个请求
        for (int i = 0; i < 10; i++) {
            final int taskId = i;
            new Thread(() -> {
                try {
                    semaphore.acquire(); // 1. 获取许可(占用一个车位)
                    System.out.println("任务 " + taskId + " 开始执行,当前并发数:"
                            + (3 - semaphore.availablePermits()));
                    // 模拟任务执行耗时
                    Thread.sleep(ThreadLocalRandom.current().nextLong(1000, 3000));
                    System.out.println("任务 " + taskId + " 执行完毕");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    semaphore.release(); // 2. 释放许可(腾出一个车位)
                }
            }).start();
        }
    }
}

运行效果(控制台会显示,任意时刻最多只有3个任务在同时执行):

任务 0 开始执行,当前并发数:1
任务 1 开始执行,当前并发数:2
任务 2 开始执行,当前并发数:3
// 任务1执行完毕后...
任务 3 开始执行,当前并发数:3
// 任务0执行完毕后...
任务 4 开始执行,当前并发数:3
...
CopyOnWriteArrayList
CountDownLatch
主要特点
两大核心方法
常见应用场景
CyclicBarrier
核心特点
进阶提示:常见陷阱
Semaphore
核心概念
代码示例:限流器