问题描述
我需要对多个资源实现线程安全的同步,每个资源一次只能被一个线程访问,但是可以同时访问不同的资源。我想出了以下代码,打算在 try-with-resources 语句中使用。
npx react-native start --reset-cache
此代码的一个问题是从未从 lockMap 中删除任何项目,而且我不知道如何以线程安全的方式执行此操作。以下绝对不是线程安全的:
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();
}
}
}
getQueueLength 的文档:
返回等待线程数的估计 获取这个锁。该值只是一个估计值,因为数量 线程可能会在此方法遍历时动态更改 内部数据结构。该方法设计用于 监控系统状态,不用于同步 控制。
有没有人知道解决方案?是否有不同的策略来实现我的目标?
解决方法
经过更多的实验,我想出了下面的代码,谁能评论一下这是否是一个好方法,代码是否正确?
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,oldValue) -> oldValue == null ? 0 : --oldValue);
if (claimsPerLock.get(key) <= 0)
{
lockMap.remove(key);
claimsPerLock.remove(key);
}
}
}
}