cor*_*iKa 7 java concurrency reentrantreadwritelock
假设我有两个关键资源,foo和bar.我保护他们一些ReentrantReadWriteLocks
ReentrantReadWriteLock foo = new RRWL() ...
ReentrantReadWriteLock bar = new RRWL() ...
Run Code Online (Sandbox Code Playgroud)
大多数操作只使用foo OR bar,但其中一些恰巧使用两者.现在使用单个锁时,您不能只这样做:
void foo() {
foo.writeLock().lock();
privateWorkOnFoo();
foo.writeLock().unlock();
}
Run Code Online (Sandbox Code Playgroud)
如果抛出异常,你的foo将永远被锁定.相反,你把它包起来,就像
void foo() {
try {
foo.writeLock().lock();
privateWorkOnFoo();
} finally { foo.writeLock().unlock(); }
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我需要同时工作呢?将它们放在一个块中是否安全?
try {
foo.writeLock().lock();
bar.writeLock().lock();
magic();
} finally {
bar.writeLock().unlock();
foo.writeLock().unlock();
}
Run Code Online (Sandbox Code Playgroud)
或者是否有必要为每个锁提供自己的块:
try {
foo.writeLock().lock();
try {
bar.writeLock().lock();
magic();
} finally {
bar.writeLock().unlock();
}
} finally {
foo.writeLock().unlock();
}
Run Code Online (Sandbox Code Playgroud)
我不可能是第一个很难对此进行调查的人...我知道选项2有"防弹",但它也是一个相当多的维护.选项1是否可以接受?
小智 7
选项1没问题.它被称为两种锁定变体.如果你看一下LinkedBlockingQueue操作,比如remove,它会锁定putLock和takeLock.以下是JDK的功能示例:
public boolean remove(Object o) {
if (o == null) return false;
fullyLock();
try
{
// ...
}
finally {
fullyUnlock();
}
}
/**
* Lock to prevent both puts and takes.
*/
void fullyLock() {
putLock.lock();
takeLock.lock();
}
/**
* Unlock to allow both puts and takes.
*/
void fullyUnlock() {
takeLock.unlock();
putLock.unlock();
}
Run Code Online (Sandbox Code Playgroud)
选项1实际上比选项2更安全,因为如果在选项2中引发异常,则第二个锁(foo)不会被解锁:解锁不会在finally块中进行。
另外,在操纵两个锁时要非常小心,因为如果一个线程foo然后锁bar,而另一个线程bar然后锁,则很有可能发生死锁foo。