java - 检查是否持有锁,如果空闲则不锁

标签 java multithreading reentrantlock

我有多个计数器对象的情况。每个计数器对象可以同时由多个线程递增,因此所有对象都有一组ReentrantLock,而且效果很好-每个对象在给定的时刻只能由一个线程修改。
这里有个要点:有一个过程每15分钟运行一次,并收集所有计数器对象,进行一些计算并清除计数器。该线程没有锁定任何东西,因此存在以下情况:

  • 递增_线程正在获取计数器对象并递增一些计数器
  • clearing_thread正在获取所有计数器对象,进行一些计算并清除计数器
  • clearing_thread将计数器对象保存到缓存
  • 递增_线程将计数器对象保存到缓存

  • 在这种情况下,计数器对象之一被弄乱了,因为最后清除操作被丢弃,并且计数器的状态与清除之前的状态相同。
    我想要的是:
  • 所有incrementing_threads都锁定在特定的计数器对象上,因此每个对象只能由一个线程修改,但同时独立的对象可以由多个线程修改,这项工作已经非常出色了。
  • 当clearing_thread启动时,它设置某种标志,该标志将由所有incrementing_threads读取,并且它们必须等待,直到该标志被取消为止。

  • 我有备份计划:
  • 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();
    

    最佳答案

    您可以使用ReadWriteLock

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

  • 您仍需要为每个计数器设置单独的锁。

    关于java - 检查是否持有锁,如果空闲则不锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64023620/

    相关文章:

    Java Switch语句困惑

    java - JComboBox ,如何知道一次选择了哪个特定选项

    java - 同步方法不断被调用

    java - 线程共享的 ReentrantLock 似乎不支持锁定

    java - 如何访问 jar 文件中文件夹的内容?

    java - 两种代码哪一种更正确?

    java - Eclipse 中的多线程调试

    c++ - 如何在不使用 <mutex> 的情况下在 C++11 中实现多线程安全单例

    java - java中的可重入锁

    java - java中使用可重入锁限制对共享数据的访问