首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >线程安全锁定/同步为每个资源具有多个资源的许可

线程安全锁定/同步为每个资源具有多个资源的许可
EN

Stack Overflow用户
提问于 2021-02-20 12:53:26
回答 1查看 130关注 0票数 0

我需要实现多个资源的线程安全同步,其中每个资源一次可以由一个线程访问,但不同的资源可以同时访问。我已经提出了下面的代码,用于一条“尝试资源”语句中。

代码语言:javascript
复制
public class Gatekeeper implements AutoCloseable
{
   private static final ConcurrentMap<Long, ReentrantLock> lockMap = new ConcurrentHashMap<>();
   private final        ReentrantLock                      lock;
   private final        Long                               key;

   public Gatekeeper(Long key)
   {
      this.key = key;
      lock = lockMap.computeIfAbsent(key, (Long absentKey) -> new ReentrantLock(true)); // computeIfAbsent is an atomic operation
      try
      {
         lock.tryLock(30, TimeUnit.SECONDS);
      }
      catch (InterruptedException e)
      {
         Thread.currentThread().interrupt();
         throw new Something(":(", e);
      }
   }

   @Override
   public void close()
   {
      if(lock.isHeldByCurrentThread())
      {
         lock.unlock();
      }
   }
}

这段代码的一个问题是,从来没有从lockMap中删除任何项,而且我也不知道如何实现线程安全。以下是绝对不安全的线程:

代码语言:javascript
复制
@Override
public void close()
{
   if (lock.isHeldByCurrentThread())
   {
      if (lock.getQueueLength() == 1) // todo: getQueueLength is meant for system monitoring purposes only
      {
         lockMap.remove(key); // todo: not thread-safe, queuelength could have changed by now
      }

      lock.unlock();
   }
}

getQueueLength的文档:

返回等待获取此锁的线程数的估计值。该值只是一个估计值,因为当此方法遍历内部数据结构时,线程数可能会动态变化。该方法用于监测系统状态,而不是用于同步控制。

有人知道解决这个问题的办法吗?是否有不同的策略来实现我的目标?

EN

回答 1

Stack Overflow用户

发布于 2021-02-20 13:38:43

经过更多的实验,我想出了下面的代码,有人能评论一下这是否是一种好的方法,并且代码是正确的吗?

代码语言:javascript
复制
public class Gatekeeper implements AutoCloseable
{
   private static final ConcurrentMap<Long, ReentrantLock> lockMap = new ConcurrentHashMap<>();
   private final        ReentrantLock                      lock;
   private final        Long                               key;

   private static final ConcurrentMap<Long, Integer> claimsPerLock = new ConcurrentHashMap<>();
   private static final Object                       mutex   = new Object();


   public Gatekeeper(Long key)
   {
      this.key = key;
      
      synchronized (mutex)
      {
         lock = lockMap.computeIfAbsent(key, (Long absentKey) -> new ReentrantLock(true));
         claimsPerLock.compute(key, (k, oldValue) -> oldValue == null ? 1 : ++oldValue);
      }

      try
      {
         if(!lock.tryLock(30, TimeUnit.SECONDS))
         {
            throw new SomeException("Timeout occurred while trying to acquire lock");
         }
      }
      catch (InterruptedException e)
      {
         Thread.currentThread().interrupt();
         throw new SomeException("Interrupted", e);
      }
   }

   @Override
   public void close()
   {
      lock.unlock();

      synchronized (mutex)
      {
         claimsPerLock.compute(key, (k, oldValue) -> oldValue == null ? 0 : --oldValue);
         if (claimsPerLock.get(key) <= 0)
         {
            lockMap.remove(key);
            claimsPerLock.remove(key);
         }
      }
   }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66291749

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档