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的锁时执行。
//基本上告诉其他线程当前