首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在WriteLock中有比ReadLock更优先的ReentrantReadWriteLock吗?

在WriteLock中有比ReadLock更优先的ReentrantReadWriteLock吗?
EN

Stack Overflow用户
提问于 2019-10-15 13:29:58
回答 3查看 1.1K关注 0票数 3

我读过java文档:ReentrantReadWriteLock

我看不出writeLock比readLock有什么优先权

但我也读过这样的主题:ReentrantReadWriteLock中的读写锁是否有某种关联?

我在这两个答案中都看到了以下短语:

如果读取器持有锁,线程请求写锁,则不允许读取器获取读锁,直到获得写锁的线程释放它。

更喜欢作家而不是读者。也就是说,如果写入器正在等待锁,则不允许来自其他线程的新读取器访问该资源。现有的读取器可以继续使用资源,直到释放锁为止。这就防止了所谓的“作家饥饿”。

这些短语听起来很有意义,看起来我已经在别的地方读过了。

但是很明显,这与java文档是矛盾的。

它在最新的JDK中改变了吗?它还有效吗?

如何防止作家饥饿?

EN

回答 3

Stack Overflow用户

发布于 2019-10-15 14:03:14

ReentrantReadWriteLock描述了两种操作模式:公平模式和非公平模式.你引用的选择似乎是为了描述公平模式。我不认为这两者都是矛盾的。然而,我可以看到,第一种不精确的措辞(“不允许更多的读者”)可能会导致混淆。我怀疑“更多的读者”是指来自其他线程的新读取器,而不是来自同一线程的额外重入读取器,有些人可能会将其解释为相同的读取器。如果以这种方式解释,那么它们似乎与JavaDoc一致。

票数 2
EN

Stack Overflow用户

发布于 2019-10-17 13:48:23

我创建了示例来检查:

代码语言:javascript
复制
public class RWLockTest {
    public static final Logger LOGGER = LoggerFactory.getLogger(RWLockTest.class);

       public static void main(String[] args) {
        SomeClass someClass = new SomeClass();

        Reader readerRunnable = new Reader(someClass);
        Writer writerRunnable = new Writer(someClass);
        //group 1 readers
        for (int i = 0; i < 10; i++) {
            new Thread(readerRunnable).start();
        }

        // 2 writers
        new Thread(writerRunnable).start();
        LOGGER.info("!!!!!!!!!!!!!!!WRITER_1 WAS STARTED!!!!!!!!!!!!!!!");
        new Thread(writerRunnable).start();
        LOGGER.info("!!!!!!!!!!!!!!!WRITER_2 WAS STARTED!!!!!!!!!!!!!!!");

       //group 2 readers            
       for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(readerRunnable);
            LOGGER.info(String.format("%s was submitted", thread.getId()));
            thread.start();
        }
    }

    public static class SomeClass {
        public ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

        public void read() {
            readWriteLock.readLock().lock();
            try {
                LOGGER.info(String.format("Read by %s started", Thread.currentThread().getId()));
                Thread.sleep(5000);
                LOGGER.info(String.format("Read by %s finished", Thread.currentThread().getId()));
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                readWriteLock.readLock().unlock();

            }
        }

        public void write() {
            readWriteLock.writeLock().lock();
            try {
                LOGGER.info(String.format("!!!!!!!!by %s started!!!!!!!!!!", Thread.currentThread().getId()));
                Thread.sleep(3000);
                LOGGER.info(String.format("!!!!!!!!by %s finished!!!!!!", Thread.currentThread().getId()));
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                readWriteLock.writeLock().unlock();

            }
        }

    }

    public static class Reader implements Runnable {
        SomeClass someClass;

        public Reader(SomeClass someClass) {
            this.someClass = someClass;
        }

        @Override
        public void run() {
            someClass.read();
        }
    }

    public static class Writer implements Runnable {
        SomeClass someClass;

        public Writer(SomeClass someClass) {
            this.someClass = someClass;
        }

        @Override
        public void run() {
            someClass.write();
        }
    }
}

我试着运行了很多时间,输出通常如下所示:

代码语言:javascript
复制
16:31:49.037 [main] INFO my.pack.RWLockTest - !!!!!!!!!!!!!!!WRITER_1 WAS STARTED!!!!!!!!!!!!!!!
16:31:49.040 [main] INFO my.pack.RWLockTest - !!!!!!!!!!!!!!!WRITER_2 WAS STARTED!!!!!!!!!!!!!!!
16:31:49.046 [Thread-1] INFO my.pack.RWLockTest - Read by 13 started
16:31:49.046 [main] INFO my.pack.RWLockTest - 24 was submitted
16:31:49.046 [Thread-7] INFO my.pack.RWLockTest - Read by 19 started
16:31:49.046 [Thread-4] INFO my.pack.RWLockTest - Read by 16 started
16:31:49.046 [Thread-5] INFO my.pack.RWLockTest - Read by 17 started
16:31:49.046 [Thread-0] INFO my.pack.RWLockTest - Read by 12 started
16:31:49.046 [Thread-3] INFO my.pack.RWLockTest - Read by 15 started
16:31:49.047 [main] INFO my.pack.RWLockTest - 25 was submitted
16:31:49.046 [Thread-9] INFO my.pack.RWLockTest - Read by 21 started
16:31:49.047 [Thread-8] INFO my.pack.RWLockTest - Read by 20 started
16:31:49.047 [main] INFO my.pack.RWLockTest - 26 was submitted
16:31:49.047 [Thread-2] INFO my.pack.RWLockTest - Read by 14 started
16:31:49.047 [Thread-6] INFO my.pack.RWLockTest - Read by 18 started
16:31:49.047 [main] INFO my.pack.RWLockTest - 27 was submitted
16:31:49.048 [main] INFO my.pack.RWLockTest - 28 was submitted
16:31:49.048 [main] INFO my.pack.RWLockTest - 29 was submitted
16:31:49.048 [main] INFO my.pack.RWLockTest - 30 was submitted
16:31:49.048 [main] INFO my.pack.RWLockTest - 31 was submitted
16:31:49.049 [main] INFO my.pack.RWLockTest - 32 was submitted
16:31:49.049 [main] INFO my.pack.RWLockTest - 33 was submitted
16:31:54.047 [Thread-7] INFO my.pack.RWLockTest - Read by 19 finished
16:31:54.048 [Thread-6] INFO my.pack.RWLockTest - Read by 18 finished
16:31:54.047 [Thread-5] INFO my.pack.RWLockTest - Read by 17 finished
16:31:54.049 [Thread-2] INFO my.pack.RWLockTest - Read by 14 finished
16:31:54.051 [Thread-8] INFO my.pack.RWLockTest - Read by 20 finished
16:31:54.047 [Thread-1] INFO my.pack.RWLockTest - Read by 13 finished
16:31:54.050 [Thread-9] INFO my.pack.RWLockTest - Read by 21 finished
16:31:54.049 [Thread-4] INFO my.pack.RWLockTest - Read by 16 finished
16:31:54.049 [Thread-3] INFO my.pack.RWLockTest - Read by 15 finished
16:31:54.049 [Thread-0] INFO my.pack.RWLockTest - Read by 12 finished
16:31:54.057 [Thread-10] INFO my.pack.RWLockTest - !!!!!!!!by 22 started!!!!!!!!!!
16:31:57.057 [Thread-10] INFO my.pack.RWLockTest - !!!!!!!!by 22 finished!!!!!!
16:31:57.058 [Thread-11] INFO my.pack.RWLockTest - !!!!!!!!by 23 started!!!!!!!!!!
16:32:00.060 [Thread-11] INFO my.pack.RWLockTest - !!!!!!!!by 23 finished!!!!!!
16:32:00.061 [Thread-13] INFO my.pack.RWLockTest - Read by 25 started
16:32:00.061 [Thread-14] INFO my.pack.RWLockTest - Read by 26 started
16:32:00.061 [Thread-12] INFO my.pack.RWLockTest - Read by 24 started
16:32:00.061 [Thread-15] INFO my.pack.RWLockTest - Read by 27 started
16:32:00.061 [Thread-17] INFO my.pack.RWLockTest - Read by 29 started
16:32:00.062 [Thread-19] INFO my.pack.RWLockTest - Read by 31 started
16:32:00.062 [Thread-18] INFO my.pack.RWLockTest - Read by 30 started
16:32:00.061 [Thread-16] INFO my.pack.RWLockTest - Read by 28 started
16:32:00.062 [Thread-20] INFO my.pack.RWLockTest - Read by 32 started
16:32:00.062 [Thread-21] INFO my.pack.RWLockTest - Read by 33 started
16:32:05.060 [Thread-12] INFO my.pack.RWLockTest - Read by 24 finished
16:32:05.060 [Thread-15] INFO my.pack.RWLockTest - Read by 27 finished
16:32:05.060 [Thread-13] INFO my.pack.RWLockTest - Read by 25 finished
16:32:05.060 [Thread-17] INFO my.pack.RWLockTest - Read by 29 finished
16:32:05.060 [Thread-14] INFO my.pack.RWLockTest - Read by 26 finished
16:32:05.062 [Thread-21] INFO my.pack.RWLockTest - Read by 33 finished
16:32:05.062 [Thread-16] INFO my.pack.RWLockTest - Read by 28 finished
16:32:05.062 [Thread-19] INFO my.pack.RWLockTest - Read by 31 finished
16:32:05.062 [Thread-18] INFO my.pack.RWLockTest - Read by 30 finished
16:32:05.062 [Thread-20] INFO my.pack.RWLockTest - Read by 32 finished

这是什么意思?

正如你所看到的,我所做的如下:

  1. 运行10个线程进行阅读。所有10个线程都可以并行工作。每次读取都需要5秒。
  2. 然后我启动两个作者(一写需要3秒)
  3. 然后我开始读10个读者

如您所见,提交第一次写入(16:31:49.037 [main] INFO my.pack.RWLockTest - !!!!!!!!!!!!!!!WRITER_1 WAS STARTED!!!!!!!!!!!!!!!)到实际声明((获取锁)16:31:54.057 [Thread-10] INFO my.pack.RWLockTest - !!!!!!!!by 22 started!!!!!!!!!!)之间的延迟是5秒。这是一段读书的时间。

您还可以看到,在提交了两个编写线程之后,我们提交了10个ids为的读取器线程,从24到33,它们都是在编写线程完成工作后实际启动(获得锁)的。

因此,ids从24到33的读取器线程是在16:31:49上提交的,此时,最初的10个读取器获得了重新锁,看起来它们也能够获得重新锁,但是看起来ReentrantReadWriteLock中有一些东西可以防止它避免编写人员的饥饿。最后,第二组读取器只能在16:32:00(提交后6秒)获得锁。

我不知道它是否有保证,但从我的测试中,它总是以这样的方式工作。,所以我们有一些作家优先于读者,,尽管爪哇文档说:

此类不强制对锁访问进行读取器或写入器首选项排序。

票数 2
EN

Stack Overflow用户

发布于 2019-10-23 15:07:32

最终的答案总是在代码中,所以让我们来看看。

下面是构造函数(注意:默认构造函数使用fair设置为false调用此构造函数)

代码语言:javascript
复制
public ReentrantReadWriteLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
    readerLock = new ReadLock(this);
    writerLock = new WriteLock(this);
}

因此,唯一的区别是sync属性是包含FairSync实例还是NonfairSync实例。这些实现有何不同?

下面是来自writerShouldBlock类的FairSync方法的代码:

代码语言:javascript
复制
final boolean writerShouldBlock() {
    return hasQueuedPredecessors();
}

这意味着“如果有一行”,则写入器阻塞并进入该行(队列)。然而,这与NonfairSync类的实现形成了鲜明的对比:

代码语言:javascript
复制
final boolean writerShouldBlock() {
    return false;
}

这清楚地说明了在non fair mode中,作者是如何获得优先于读者的。

最后一个关于作家饥饿的评论。在non fair mode中,这是在配套方法readerShouldBlock的实现中实现的。来自NonfairSync类中的代码的注释声明:

代码语言:javascript
复制
    final boolean readerShouldBlock() {
        /* As a heuristic to avoid indefinite writer starvation,
         * block if the thread that momentarily appears to be head
         * of queue, if one exists, is a waiting writer.  This is
         * only a probabilistic effect since a new reader will not
         * block if there is a waiting writer behind other enabled
         * readers that have not yet drained from the queue.
         */
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58395939

复制
相关文章

相似问题

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