资源节约内存上的Java读写锁

资源节约内存上的Java读写锁,java,multithreading,concurrency,locking,concurrenthashmap,Java,Multithreading,Concurrency,Locking,Concurrenthashmap,内存中有大量R类型的对象。修改对象需要写锁,读取对象需要读锁。我可以将ReadWriteLock存储为类R的私有成员,但是,我希望节省内存。在任何时候,只有一小部分对象正在被修改或读取。有多种方法可以决定不存储特定资源的读写锁(例如,如果一段时间内未对其进行读写,则为t)。出于这个问题的目的,假设可以定期确定可以删除资源的锁。但是,请记住,在线程中删除资源锁时,一个或多个其他线程可能会尝试修改或读取资源。所有这些都发生在多线程环境中。如何以最少的锁定量实现这一点 例如,一种方法是将读写锁存储在并

内存中有大量R类型的对象。修改对象需要写锁,读取对象需要读锁。我可以将ReadWriteLock存储为类R的私有成员,但是,我希望节省内存。在任何时候,只有一小部分对象正在被修改或读取。有多种方法可以决定不存储特定资源的读写锁(例如,如果一段时间内未对其进行读写,则为t)。出于这个问题的目的,假设可以定期确定可以删除资源的锁。但是,请记住,在线程中删除资源锁时,一个或多个其他线程可能会尝试修改或读取资源。所有这些都发生在多线程环境中。如何以最少的锁定量实现这一点

例如,一种方法是将读写锁存储在并发映射中:

Map Map=new ConcurrentHashMap();
确定可以删除资源的读写锁后,将其从映射中删除。然而,如上所述,在决定删除条目之后和条目被删除之前,其他线程可能希望获得读或写锁

您可能认为可以使用computeifabsentremove的组合。然而,这是行不通的。例如:

问题是线程1的锁对象与线程3获得的锁不同,并且错误地允许两次写入同时发生。右边的数字表示执行顺序

答案不需要使用上面示例中给出的并发映射,但它似乎是一个良好的开端,并提供了对锁的并发访问。如果您确实使用并发映射,请随意将ReadWriteLock包装到另一个结构中,或者创建您自己的ReadWriteLock版本

总之,问题是如何维护资源集合的读写锁,而不必为集合中的每个对象存储读写锁并最小化锁争用

问题是如何维护资源集合的读写锁,而不必为集合中的每个对象存储读写锁并最小化锁争用

你考虑过使用条纹锁吗?(例如,)


基本上,它是M个数据的N个锁的集合,其中N您可以使用方法
compute
computeIfPresent
。重要的是在消费者内部进行添加/锁定/移除,以使其原子化

注意:您在示例中使用了
putIfAbsent
,但它返回的是以前的指定值,而不是新的指定值

公共静态类锁
{
私有ConcurrentHashMap锁=新ConcurrentHashMap();
公共无效锁(R R,功能whichLock)
{
锁。计算(r,(键,锁)->{
REENTRANDREADWRITELOCK actualLock=lock==null?新的REENTRANDREADWRITELOCK():lock;
whichLock.apply(actualLock.lock();
返回实际时钟;
});
}
公共无效解锁(右,功能whichLock)
{
locks.computefpresent(r,(键,锁)->{
whichLock.apply(lock.unlock();
return lock;//如果锁已解锁(请参阅清理),则可以在此处返回null以立即删除它
});
}
公共空间清理()
{
对于(R:new ArrayList(locks.keySet()))
{
locks.computeIfPresent(r,(key,lock)->locks.get(r).isWriteLocked()
||locks.get(r).getReadLockCount()!=0?lock:null);
}
}
}
注意我如何使用

  • compute
    lock
    中创建新锁并立即锁定
  • computeIfPresent
    unlock
    中检查是否有锁
  • computeIfPresent
    cleanUp
    中检查在检查读锁计数时是否需要一个锁,而不需要另一个线程锁定写锁
现在,
unlock
相当无用(除了空检查,这只是一种预防措施)。在
unlock
中返回
null
将很好地清除不必要的锁,并使
cleanUp
过时,但可能会增加创建新锁的需要。这取决于锁的使用频率


当然,您可以为读/写添加方便的方法,而不必提供getter
,这是家庭作业还是类似的东西?你真正的问题是什么?这似乎是一个有趣的问题,但我不知道您遇到了什么问题。在从地图中删除
R
之前,请等待锁发出通知。@MalteHartwig No not homebook。基本上,如何维护对象集合的读写锁,而不必为每个对象存储读写锁。@jaychang0917 ReadWriteLocks不会通知锁定和解锁。如果你认为你有一个解决方案,请提供一些代码。@MalteHartwig嗯,我曾经是一名计算机科学教授:)我在最后添加了一个问题的摘要。此外,我已经在上面的代码中展示了我的一些努力;使用concurrenthashmap和putifabsent,删除组合。这看起来非常好。我确实在代码中修复了putifabsent的问题。为什么你说unlock毫无用处?java文档说不要使用isWriteLocked和getReadLockCount进行同步控制(可能不是这里所做的),但是
//--Thread1 write lock--
ReadWriteLock rwl = map.computeIfAbsent(r, r -> new ReadWriteLock()); // 1
rwl.writeLock.lock();                                        // 4
//Modify r here

//--Thread2: Removing entry--
map.remove(r);                                               // 2

//Thread3: write lock
ReadWriteLock rwl = map.computeIfAbsent(r, r-> new ReadWriteLock()); // 3
rwl.writeLock.lock();                                        // 5
//Modify r here.
public static class Locks<R>
{
    private ConcurrentHashMap<R, ReentrantReadWriteLock> locks = new ConcurrentHashMap<>();

    public void lock(R r, Function<ReentrantReadWriteLock, Lock> whichLock)
    {
        locks.compute(r, (key, lock) -> {
            ReentrantReadWriteLock actualLock = lock == null ? new ReentrantReadWriteLock() : lock;
            whichLock.apply(actualLock).lock();
            return actualLock;
        });
    }

    public void unlock(R r, Function<ReentrantReadWriteLock, Lock> whichLock)
    {
        locks.computeIfPresent(r, (key, lock) -> {
            whichLock.apply(lock).unlock();
            return lock; // you could return null here if lock is unlocked (see cleanUp) to remove it immediately
        });
    }

    public void cleanUp()
    {
        for (R r : new ArrayList<>(locks.keySet()))
        {
            locks.computeIfPresent(r, (key, lock) -> locks.get(r).isWriteLocked()
                                                     || locks.get(r).getReadLockCount() != 0 ? lock : null);
        }
    }
}