我需要实现多个资源的线程安全同步,其中每个资源一次可以由一个线程访问,但不同的资源可以同时访问。我已经提出了下面的代码,用于一条“尝试资源”语句中。
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中删除任何项,而且我也不知道如何实现线程安全。以下是绝对不安全的线程:
@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的文档:
返回等待获取此锁的线程数的估计值。该值只是一个估计值,因为当此方法遍历内部数据结构时,线程数可能会动态变化。该方法用于监测系统状态,而不是用于同步控制。
有人知道解决这个问题的办法吗?是否有不同的策略来实现我的目标?
发布于 2021-02-20 13:38:43
经过更多的实验,我想出了下面的代码,有人能评论一下这是否是一种好的方法,并且代码是正确的吗?
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);
}
}
}
}https://stackoverflow.com/questions/66291749
复制相似问题