3

我研究 ReentrantReadWriteLock

来自 java 文档的片段:

直到当前等待的最早的写线程获得并释放写锁之后,该线程才会获得读锁

据我了解。

读取持续时间- 1 个时间单位

写入持续时间- 3 个时间单位

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

因此,我期望以下顺序:

  1. 先写
  2. 第二次写

我的实验代码:

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. 第二次写

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

是否可以打破 FIFO 排序?

更新

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

第一的

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

第二:

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

我不完全理解那里写的意思但是我看到ReentrantReadWriteLock使用不同的策略来获取读锁和写锁。我建议如果 java doc 中的政治相同,就不会写两个缩进。

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

4

1 回答 1

3

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

private static ReadWriteLock lock = new ReentrantReadWriteLock(true);

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

当构造为公平时,线程使用近似到达顺序策略竞争进入。当当前持有的锁被释放时,等待时间最长的单个写入线程将被分配写入锁,或者如果有一组读取线程等待的时间比所有等待写入线程的时间长,则将为该组分配读取锁。

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

于 2014-04-16T09:34:16.137 回答