java - 重入读写锁。读写优先

标签 java multithreading concurrency locking reentrantreadwritelock

我研究 ReentrantReadWriteLock

来自 java 文档的片段:

The thread will not acquire the read lock until after the oldest currently waiting writer thread has acquired and released the write lock

据我了解。

阅读时长- 1个时间单位

写入时长- 3个时间单位

  1. 时间 0 - 获得写锁
  2. 时间 1 - 读锁尝试读
  3. 时间 2 - 写锁尝试写

因此我期望以下顺序:

  1. 先写
  2. 第二次写
  3. 阅读

我的实验代码:

public class RWLockCalculator {
    static long initTime = System.currentTimeMillis();
    private static int calculatedValue = 0;
    private static ReadWriteLock lock = new ReentrantReadWriteLock();
    public void calculate(int value) {
        lock.writeLock().lock();
        try {           
            System.out.println("write lock acquired at "+ (System.currentTimeMillis()-RWLockCalculator.initTime));
            this.calculatedValue = 1;
            Thread.sleep(300);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            lock.writeLock().unlock();
        }
    }

    public int getCalculatedValue() {
        lock.readLock().lock();
        try {           
            System.out.println("read lock acquired at "+ (System.currentTimeMillis()-RWLockCalculator.initTime));
            Thread.sleep(100);
            return calculatedValue;
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return -1;
        } finally {
            lock.readLock().unlock();
        }
    }
}

class Test {
    public static void main(String[] args) throws InterruptedException {
        new WriteThread().start();
        Thread.sleep(100);
        new ReadThread().start();
        Thread.sleep(100);
        new WriteThread().start();

    }
}

class ReadThread extends Thread {
    @Override
    public void run() {
        System.out.println(new RWLockCalculator().getCalculatedValue() + ", " + (System.currentTimeMillis() - RWLockCalculator.initTime));
    }
}

class WriteThread extends Thread {
    @Override
    public void run() {
        new RWLockCalculator().calculate(99);
        System.out.println("I have written in  " + (System.currentTimeMillis() - RWLockCalculator.initTime));
    }
}

输出:

write lock acquired at 0
I have written in  300
read lock acquired at 300
1, 400
write lock acquired at 400
I have written in  700

因此我得到

  1. 先写
  2. 阅读
  3. 第二次写

为什么我会得到这个结果?

是否可以打破 FIFO 顺序?

更新

请比较 java 文档中的两个兄弟片段(关于公平模式):

首先

尝试获取公平读锁(不可重入)的线程将在持有写锁或有等待写入线程的情况下阻塞。直到当前最旧的等待写线程获得并释放写锁后,该线程才会获得读锁。当然,如果一个正在等待的写者放弃等待,留下一个或多个读者线程作为队列中最长的等待者,写锁空闲,那么这些读者将被分配读锁。

第二个:

尝试获取公平写锁(不可重入)的线程将阻塞,除非读锁和写锁都是空闲的(这意味着没有等待线程)。 (请注意,非阻塞 ReentrantReadWriteLock.ReadLock.tryLock() 和 ReentrantReadWriteLock.WriteLock.tryLock() 方法不遵守此公平设置,如果可能,将获取锁,而不管等待线程如何。)

我不完全理解那里所写内容的含义但是我看到 ReentrantReadWriteLock 使用不同的策略来获取读锁和写锁。我建议如果 java 文档中的政治相同,则不会写两个缩进。

ReadLock 可以共享锁。只有一个区别吗?

最佳答案

首先,ReentrantReadWriteLock 应该在公平模式下创建,以施加特定的锁获取顺序:

private static ReadWriteLock lock = new ReentrantReadWriteLock(true);

然后,javadoc非常清楚地描述了您的案例:

When constructed as fair, threads contend for entry using an approximately arrival-order policy. When the currently held lock is released either the longest-waiting single writer thread will be assigned the write lock, or if there is a group of reader threads waiting longer than all waiting writer threads, that group will be assigned the read lock.

由于您的读取线程比第二个写入线程等待的时间更长,因此它在写入线程之前获取锁。

关于java - 重入读写锁。读写优先,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23104012/

相关文章:

java - 如何在 Java 中验证 Date 对象

android - 在 Android 的主线程中使用 OpenGL

c++ - 线程中的堆栈大小在 C++ 中定义了什么?

java - 线程通过调用interrupt()被中断,但是Thread.isInterrupted()返回false

java - Api Java弹性搜寻|通过传递列表并返回所有匹配项进行搜索

java - netbeans 平台应用程序的多个实例

python - 阻塞 Tkinter 接口(interface),直到线程完成其任务

java - 如何使用单 Spark 上下文在 Apache Spark 中运行并发作业(操作)

java - 使用 volatile 字段安全发布对象

Java:将对象转换为泛型