You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用ReentrantLock实现数组每秒清理且不阻塞非清理线程?

用ReentrantLock实现数组定时清理与并发添加的方案

嘿,针对你想用ReentrantLock实现数组每秒自动清理,清理时阻塞所有修改操作、非清理时修改无需等待的需求,我整理了一个贴合场景的解决方案,连Netty环境的适配细节也给你考虑到了:

核心思路拆解

  1. 锁的使用策略:
    • 对于add操作,用ReentrantLock的非阻塞获取锁(tryLock()):如果当前没有在清理,直接拿到锁修改数组;如果清理线程正在占用锁,直接跳过(或者按业务需求处理),完全不阻塞其他正常请求。
    • 清理线程则独占锁(lock()),确保清理期间绝对没有其他线程修改数组,保证数据一致性。
  2. 定时任务选型:用定时线程池(或者Netty自带的EventLoop定时API)每秒触发一次清理,和Netty的EventLoop线程模型兼容。

完整代码示例

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class ArrayCleaner {
    private final List<Object> array = new ArrayList<>();
    private final ReentrantLock lock = new ReentrantLock();
    private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

    public ArrayCleaner() {
        // 初始化定时任务:每秒执行一次清理
        scheduler.scheduleAtFixedRate(this::cleanArray, 1, 1, TimeUnit.SECONDS);
    }

    public void addToArray(Object a) {
        // 尝试获取锁,拿到就修改数组,拿不到直接跳过(可根据业务调整)
        if (lock.tryLock()) {
            try {
                array.add(a);
            } finally {
                // 必须在finally里释放锁,防止异常导致锁泄漏
                lock.unlock();
            }
        } else {
            // 这里示例是直接打印提示,你可以改成缓存到临时队列、重试等逻辑
            System.out.println("数组正在清理,本次添加请求跳过");
        }
    }

    private void cleanArray() {
        // 独占锁,确保清理期间没有其他线程修改数组
        lock.lock();
        try {
            System.out.printf("开始清理数组,当前元素数:%d%n", array.size());
            array.clear();
            System.out.println("数组清理完成");
        } finally {
            lock.unlock();
        }
    }

    // 关闭定时任务,避免内存泄漏
    public void shutdown() {
        scheduler.shutdown();
        try {
            if (!scheduler.awaitTermination(1, TimeUnit.SECONDS)) {
                scheduler.shutdownNow();
            }
        } catch (InterruptedException e) {
            scheduler.shutdownNow();
        }
    }
}

Netty场景适配说明

因为你提到Netty EventLoop会调用网络处理器,为了契合Netty的线程模型,你可以把定时任务替换成Netty EventLoop的API,不用额外创建线程池:

// 假设你已经有可用的EventLoop实例(比如从EventLoopGroup中获取)
EventLoop eventLoop = ...;
// 用Netty的定时任务触发清理
eventLoop.scheduleAtFixedRate(this::cleanArray, 1, 1, TimeUnit.SECONDS);

这样清理任务会在Netty的IO线程中执行,避免线程上下文切换的开销。

关键细节提醒

  • tryLock()的灵活用法:如果你的业务不允许丢弃添加请求,可以用tryLock(100, TimeUnit.MILLISECONDS)设置一个短暂等待时间,或者把无法添加的元素放到一个临时队列,等清理完成后再批量写入数组。
  • 锁的绝对释放:无论add还是clean操作,一定要在finally块里释放锁,哪怕出现异常也不会导致死锁。
  • 资源回收:定时任务的线程池(或Netty EventLoop)要在程序退出时正确关闭,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Lost2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:30:43