有时,我在一些Java代码中发现,他们使用嵌套锁来实现同步方法。代码如下
// lock for appending state management
final Lock appendLock = new ReentrantLock();
// global lock for array read and write management
final ReadWriteLock arrayReadWritelock = new ReentrantReadWriteLock();
final Lock arrayReadLock = arrayReadWritelock.readLock();
final Lock arrayWriteLock = arrayReadWritelock.writeLock();
private MapEntry acquireNew(int length) throws IOException {
MapEntry mapEntry = null;
try {
arrayReadLock.lock(); //THE FIRST LOCK
IMappedPage toAppendIndexPage = null;
long toAppendIndexPageIndex = -1L;
long toAppendDataPageIndex = -1L;
long toAppendArrayIndex = -1L;
try {
appendLock.lock(); //THE SECOND LOCK
if (this.isFull()) {
throw new IOException("ring space of java long type used up, the end of the world!!!");
}
if (this.headDataItemOffset + length > DATA_PAGE_SIZE) {
if (this.headDataPageIndex == Long.MAX_VALUE) {
this.headDataPageIndex = 0L;
} else {
this.headDataPageIndex++;
}
this.headDataItemOffset = 0;
}
toAppendDataPageIndex = this.headDataPageIndex;
..........
..........
mapEntry = new MapEntry(toAppendArrayIndex, length, toAppendIndexItemOffset, toAppendIndexPage, this.dataPageFactory);
mapEntry.MarkAllocated();
this.totalEntryCount.incrementAndGet();
this.totalSlotSize.addAndGet(length);
this.arrayHeadIndex.incrementAndGet();
IMappedPage metaDataPage = this.metaPageFactory.acquirePage(META_DATA_PAGE_INDEX);
ByteBuffer metaDataBuf = metaDataPage.getLocal(0);
metaDataPage.setDirty(true);
} finally {
appendLock.unlock();
}
} finally {
arrayReadLock.unlock();
}
return mapEntry;
}
这让我很困惑,因为第一个锁已经被使用了,为什么作者再次使用另一个锁呢?
发布于 2017-01-20 08:32:02
第一个锁是“读”锁,第二个锁是某种“写”锁。因此,如果您希望在写入时避免锁定读取操作,这可能是很好的,反之亦然。这可能会提高性能。但是这种事情总是有风险的,它可能会导致棘手的bug。如果只有一个锁可以同时用于读和写,那么这可能会更简单、更健壮。
发布于 2017-01-20 08:39:38
根据这些名称,我建议外层锁为readLock,内层锁为WriteLock。两者都有不同的行为。因为可能有尽可能多的锁,但是与readLocks和writeLocks相比,一个锁只能是一个锁。
所以在这个例子中,他锁住了读,所以如果他不释放,就不能写(尽管在这个例子中可能有点夸张)。通常会做一些检查,看看是否应该执行写操作(不是在这种情况下),然后需要一个writingLock来执行写操作线程安全。
ReentrantLock是这种机制的默认实现,您可以使用它来观察/测试这些机制
发布于 2017-01-20 08:45:05
它增加了锁定粒度。
例如,假设您想要使用锁保护某些变量a
和b
。你可以使用一个大锁:
public class BigLockDemo {
private final Lock bigLock = new ReentrantLock();
private int a;
private int b;
public int getA() {
bigLock.lock();
try {
return a;
} finally {
bigLock.unlock();
}
}
public void setA(int a) {
bigLock.lock();
try {
this.a = a;
} finally {
bigLock.unlock();
}
}
public int getB() {
bigLock.lock();
try {
return b;
} finally {
bigLock.unlock();
}
}
public void setB(int b) {
bigLock.lock();
try {
this.b = b;
} finally {
bigLock.unlock();
}
}
public void setAB(int a, int b) {
bigLock.lock();
try {
// nobody holding the lock may see simultaneously
// the new value of a and the old value of b
this.a = a;
this.b = b;
} finally {
bigLock.unlock();
}
}
}
但是,如果一个线程只读/写a
,而另一个线程只读/写B
,则它们必须进行不必要的同步(例如,getA()
将阻塞,而setB()
持有锁)。
使用两个锁,您可以避免这个问题:
public class ABLockDemo {
private final Lock aLock = new ReentrantLock();
private final Lock bLock = new ReentrantLock();
private int a;
private int b;
public int getA() {
aLock.lock();
try {
return a;
} finally {
aLock.unlock();
}
}
public void setA(int a) {
aLock.lock();
try {
this.a = a;
} finally {
aLock.unlock();
}
}
public int getB() {
bLock.lock();
try {
return b;
} finally {
bLock.unlock();
}
}
public void setB(int b) {
bLock.lock();
try {
this.b = b;
} finally {
bLock.unlock();
}
}
public void setAB(int a, int b) {
aLock.lock();
bLock.lock();
try {
// nobody holding the locks may see simultaneously
// the new value of a and the old value of b
this.a = a;
this.b = b;
} finally {
aLock.unlock();
bLock.unlock();
}
}
}
如果您想同时保护a
和b
,则需要同时持有这两个锁。
https://stackoverflow.com/questions/41759064
复制