Java:锁定在同一元素上工作的函数

Java:锁定在同一元素上工作的函数,java,synchronization,locking,synchronized,Java,Synchronization,Locking,Synchronized,有许多线程处理同一映射上的元素,每个线程都有一个代码,例如: THREAD_1 works on an element with code "1234" THREAD_2 works on an element with code "1234" THREAD_3 works on an element with code "9876" etc... 元件不是永久性的,即螺纹_1可能会移除元件“1234”,然后再次插入。我想要的是,当线程1正在处理元素“1234”(也正在删除它)时,线程2必须等

有许多线程处理同一映射上的元素,每个线程都有一个代码,例如:

THREAD_1 works on an element with code "1234"
THREAD_2 works on an element with code "1234"
THREAD_3 works on an element with code "9876"
etc...
元件不是永久性的,即螺纹_1可能会移除元件“1234”,然后再次插入。我想要的是,当线程1正在处理元素“1234”(也正在删除它)时,线程2必须等待

有办法吗

一个可能的解决方案可能是在HashMap中插入一个伪元素,然后在该元素上使用“synchronized”子句强制执行同步。你觉得怎么样?(显然,如果线程删除了带有关联代码的元素,伪元素也会保留在映射中)

您应该使用

一个哈希表,支持检索的完全并发性和更新的可调整预期并发性

检索操作(包括get)通常不会阻止,因此可能与更新操作(包括put和remove)重叠

更新操作之间允许的并发性由可选的concurrencyLevel构造函数参数(默认值16)指导,该参数用作内部大小调整的提示。该表是内部分区的,以尝试允许指定数量的并发更新,而不会产生争用。由于哈希表中的位置基本上是随机的,因此实际的并发性会有所不同

你应该使用

一个哈希表,支持检索的完全并发性和更新的可调整预期并发性

检索操作(包括get)通常不会阻止,因此可能与更新操作(包括put和remove)重叠

更新操作之间允许的并发性由可选的concurrencyLevel构造函数参数(默认值16)指导,该参数用作内部大小调整的提示。该表是内部分区的,以尝试允许指定数量的并发更新,而不会产生争用。由于哈希表中的位置基本上是随机的,因此实际的并发性会有所不同


我们用一种叫做锁图的东西

锁图基本上是:

Map<Object, ReadWriteLock>
这很方便

一旦获得了锁,就可以根据需要锁定它,以控制对对象的访问


我们要做的另一件事是使用LRU映射(使用LinkedHashMap——请参见),以便旧对象键在未使用时可以从末端脱落。

我们使用一种称为锁映射的东西

锁图基本上是:

Map<Object, ReadWriteLock>
这很方便

一旦获得了锁,就可以根据需要锁定它,以控制对对象的访问


我们要做的另一件事是使用LRU映射(使用LinkedHashMap——请参阅),以便旧的对象键在未使用时从末端脱落。

鉴于您的特定问题,没有一个java标准对象可以解决您的所有问题。我认为以下解决方案是正确的,不会在锁映射中保留任何不必要的键或值:

// we don't use a ConcurrentHashMap, because we have some other operations 
// that need to be performed in atomically with map.put and map.remove.
// ConcurrentHashMap would of course also work, but it doesn't remove the 
// need for external synchronization in in our case.
Map<String, CountingLock> locksMap = new HashMap<String, CountingLock>();
...

HttpResponse myFunction(String key) {

    CountingLock lock;
    synchronized(locksMap){
        lock = locksMap.get(key);
        if(lock == null){
            lock = new CountingLock();
            locksMap.put(key, lock);
        }
        lock.prepare(); // has to be done while holding the lock of locksMap.
                        // basically tells other threads that the current 
                        // thread intends to acquire the lock soon. This way,
                        // the other threads know not to remove this lock 
                        // from locksMap as long as another one has indicated
                        // that he is going to need it soon.
    }

    lock.lock(); // has to be done while NOT holding the lock of locksMap,
                 // or we risk deadlock situations.

    try {
        // ...
        // work
        // ...
    } finally {
        synchronized(locksMap) {
            if(lock.unlock() == 0){
                // no other thread is intending to use this lock any more. 
                // It is safe to remove it from the map. The next thread 
                // will just have to recreate a new lock for the same key.
                locksMap.remove(key);
            }
        }
    }

    return SOMETHING;    
}

private static class CountingLock {
    // The number of threads that are trying to access the protected Key
    private AtomicInteger interestedThreads = new AtomicInteger(0);

    private Lock lock = new ReentrantLock();

    public void prepare(){
        interestedThreads.incrementAndGet();
    }

    public void lock(){
        lock.lock();
    }

    public int unlock(){
        lock.unlock();
        return interestedThreads.decrementAndGet();              
    }
}
//我们不使用ConcurrentHashMap,因为我们还有其他一些操作
//这需要通过map.put和map.remove以原子方式执行。
//ConcurrentHashMap当然也可以工作,但它不会删除
//在我们的例子中,需要外部同步。
Map locksMap=newhashmap();
...
HttpResponse myFunction(字符串键){
计数锁;
已同步(锁定映射){
lock=locksMap.get(钥匙);
if(lock==null){
lock=新的CountingLock();
锁(钥匙,锁);
}
lock.prepare();//必须在按住locksMap的锁时执行。
//基本上告诉其他线程当前
//线程打算很快获得锁。这样,
//其他线程知道不要移除此锁
//从locksMap,只要另一个指示
//他很快就会需要它。
}
lock.lock();//必须在不持有locksMap的锁的情况下执行,
//或者我们冒着僵局的风险。
试一试{
// ...
//工作
// ...
}最后{
已同步(锁定映射){
如果(lock.unlock()==0){
//没有其他线程打算再使用此锁。
//从映射中删除它是安全的。下一个线程
//只需为同一把钥匙重新创建一个新锁。
锁。取下(钥匙);
}
}
}
归还某物;
}
私有静态类计数锁{
//尝试访问受保护密钥的线程数
私有AtomicInteger interestedThreads=新的AtomicInteger(0);
private Lock=new ReentrantLock();
公众假期准备(){
interestedThreads.incrementAndGet();
}
公共无效锁(){
lock.lock();
}
公共int解锁(){
lock.unlock();
返回感兴趣的线程。decrementAndGet();
}
}

此代码在所有情况下都应按预期工作。这是一个需要解决的有趣问题:-)

鉴于您的特定问题,没有一个java标准对象可以解决您的所有问题。我认为以下解决方案是正确的,不会在锁映射中保留任何不必要的键或值:

// we don't use a ConcurrentHashMap, because we have some other operations 
// that need to be performed in atomically with map.put and map.remove.
// ConcurrentHashMap would of course also work, but it doesn't remove the 
// need for external synchronization in in our case.
Map<String, CountingLock> locksMap = new HashMap<String, CountingLock>();
...

HttpResponse myFunction(String key) {

    CountingLock lock;
    synchronized(locksMap){
        lock = locksMap.get(key);
        if(lock == null){
            lock = new CountingLock();
            locksMap.put(key, lock);
        }
        lock.prepare(); // has to be done while holding the lock of locksMap.
                        // basically tells other threads that the current 
                        // thread intends to acquire the lock soon. This way,
                        // the other threads know not to remove this lock 
                        // from locksMap as long as another one has indicated
                        // that he is going to need it soon.
    }

    lock.lock(); // has to be done while NOT holding the lock of locksMap,
                 // or we risk deadlock situations.

    try {
        // ...
        // work
        // ...
    } finally {
        synchronized(locksMap) {
            if(lock.unlock() == 0){
                // no other thread is intending to use this lock any more. 
                // It is safe to remove it from the map. The next thread 
                // will just have to recreate a new lock for the same key.
                locksMap.remove(key);
            }
        }
    }

    return SOMETHING;    
}

private static class CountingLock {
    // The number of threads that are trying to access the protected Key
    private AtomicInteger interestedThreads = new AtomicInteger(0);

    private Lock lock = new ReentrantLock();

    public void prepare(){
        interestedThreads.incrementAndGet();
    }

    public void lock(){
        lock.lock();
    }

    public int unlock(){
        lock.unlock();
        return interestedThreads.decrementAndGet();              
    }
}
//我们不使用ConcurrentHashMap,因为我们还有其他一些操作
//这需要通过map.put和map.remove以原子方式执行。
//ConcurrentHashMap当然也可以工作,但它不会删除
//在我们的例子中,需要外部同步。
Map locksMap=newhashmap();
...
HttpResponse myFunction(字符串键){
计数锁;
已同步(锁定映射){
lock=locksMap.get(钥匙);
if(lock==null){
lock=新的CountingLock();
锁(钥匙,锁);
}
lock.prepare();//必须在按住locksMap的锁时执行。
//基本上告诉其他线程当前