首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用嵌套锁进行同步

使用嵌套锁进行同步
EN

Stack Overflow用户
提问于 2017-01-20 16:23:36
回答 3查看 189关注 0票数 0

有时,我在一些Java代码中发现,他们使用嵌套锁来实现同步方法。代码如下

代码语言:javascript
运行
复制
// 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;
}

这让我很困惑,因为第一个锁已经被使用了,为什么作者再次使用另一个锁呢?

EN

回答 3

Stack Overflow用户

发布于 2017-01-20 16:32:02

第一个锁是“读”锁,第二个锁是某种“写”锁。因此,如果您希望在写入时避免锁定读取操作,这可能是很好的,反之亦然。这可能会提高性能。但是这种事情总是有风险的,它可能会导致棘手的bug。如果只有一个锁可以同时用于读和写,那么这可能会更简单、更健壮。

票数 1
EN

Stack Overflow用户

发布于 2017-01-20 16:39:38

根据这些名称,我建议外层锁为readLock,内层锁为WriteLock。两者都有不同的行为。因为可能有尽可能多的锁,但是与readLocks和writeLocks相比,一个锁只能是一个锁。

所以在这个例子中,他锁住了读,所以如果他不释放,就不能写(尽管在这个例子中可能有点夸张)。通常会做一些检查,看看是否应该执行写操作(不是在这种情况下),然后需要一个writingLock来执行写操作线程安全。

ReentrantLock是这种机制的默认实现,您可以使用它来观察/测试这些机制

票数 0
EN

Stack Overflow用户

发布于 2017-01-20 16:45:05

它增加了锁定粒度。

例如,假设您想要使用锁保护某些变量ab。你可以使用一个大锁:

代码语言:javascript
运行
复制
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()持有锁)。

使用两个锁,您可以避免这个问题:

代码语言:javascript
运行
复制
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();
        }
    }
}

如果您想同时保护ab,则需要同时持有这两个锁。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41759064

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档