检查锁是否被持有但如果它是空闲的则不锁定它

Check if lock is held but not lock it if it is free

我有多个计数器对象的场景。每个计数器对象可以同时由多个线程递增,因此所有对象都有一组 ReentrantLock,这很好用 - 每个对象在给定时刻只能由一个线程修改。

关键在于:有一个进程每 15 分钟运行一次,收集所有计数器对象,进行一些计算并清除计数器。该线程没有锁定任何东西,所以有以下情况:

  1. incrementing_thread 正在获取计数器对象并递增一些计数器
  2. clearing_thread 正在获取所有计数器对象,进行一些计算并清除计数器
  3. clearing_thread 将计数器对象保存到缓存
  4. incrementing_thread 将计数器对象保存到缓存

在这种情况下,其中一个计数器对象被弄乱了,因为最后清除操作被丢弃并且计数器的状态与清除前相同。

我想要的:

我有后备计划:

如您所见,我有一些选择,但我想知道是否有更好的方法。

更新 我被要求提供代码,所以它就在那里。

下面是增加对象计数器的方法之一的示例。

public void sipIncomingCall(String objName) {
    try {
        lock(objName);
        Stats stat = getStatisticsForObj(objName);
        long l = stat.getSipIncomingConnections().incrementAndGet();
        stat.getSipConnectionsSum().incrementAndGet();
        LOGGER.debug("incrementing sip incoming connections to {}, objName {}", l, objName);
        putStatisticsForObj(objName, stat);
    }finally {
        unlock(objName);
    }
}

lock() 和 unlock() 方法:

private Map<String,ReentrantLock> locks = new ConcurrentHashMap<>();
protected void lock(String key) {
    ReentrantLock lock = locks.getOrDefault(key, new ReentrantLock());
    lock.lock();
}

protected void unlock(String key){
    ReentrantLock lock = locks.get(key);
    if(lock!=null){
        lock.unlock();
    }
}

方法 getStatisticsForObj() 和 putStatisticsForObj():

private MgcfStats getStatisticsForObj(String tgName) {
    //get object from local cache (or hazelcast)
    return Cluster.getTgStatistics(tgName);
}

private void putStatisticsForObj(String tgName,MgcfStats stats){
    //saving to local cache and hazelcast
    Cluster.putTgStatistics(tgName,stats);
}

下面是来自“clearing_thread”的片段,它将所有统计对象复制到本地映射,然后清除集群中的统计信息:

    statisticsData.setObjStats(new HashMap<>(Cluster.getTgStatistics()));
    Cluster.clearTgStatistics();

您可以使用 ReadWriteLock.

  • 递增线程在递增值之前获取读锁。
  • 清理线程获取写锁。

您仍然需要为每个计数器单独锁。