【问题标题】:Check if lock is held but not lock it if it is free检查锁是否被持有,但如果它是空闲的,则不锁定它
【发布时间】:2020-09-23 08:08:06
【问题描述】:

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

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

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

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

我想要什么:

  • 所有 incrementing_threads 都锁定在特定的计数器对象上,因此每个对象只能由一个线程修改,但同时独立的对象可以由多个线程修改,这项工作已经很棒了。
  • 当 clearing_thread 启动时,它会设置某种标志,所有 incrementing_thread 都会读取该标志,并且它们必须等到标志被解除。

我有备用计划:

  • clearing_thread 锁定所有对象,但我不喜欢这个想法,因为它可能需要很长时间,如果它阻塞其中一个对象,它可能会阻塞所有线程。
  • 我可以在 for 循环中为每个对象清除计数器,但是在清除一个对象时可以修改其他对象,这对我来说并不理想。

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

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

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

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();

【问题讨论】:

  • 请添加代码。代码说超过 1000000 个单词。
  • 我添加了代码,但同时问题已解决:)

标签: java multithreading reentrantlock


【解决方案1】:

您可以使用ReadWriteLock

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-25
    相关资源
    最近更新 更多