我研究了ReentrantReadWriteLock。
Java文档中的片段如下:
直到最老的正在等待的写线程获取并释放写锁之后,当前线程才会获取读锁
因此,我的理解是:
读持续时间- 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可以共享锁。这是唯一的区别吗?