我研究 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个时间单位
- 时间 0 - 获得写锁
- 时间 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
因此我得到
- 先写
- 阅读
- 第二次写
为什么我会得到这个结果?
是否可以打破 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/