【发布时间】:2011-11-01 04:26:41
【问题描述】:
从How to understand the “non-fair” mode of ReentrantReadWriteLock?这个问题来看,我认为无论哪个线程先获得锁,所有线程都有相同的机会。
所以我写了这段代码来测试它:
public static void main(String[] args) {
ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
final ReadLock readLock = lock.readLock();
final WriteLock writeLock = lock.writeLock();
// hold the write lock 3s at first
new Thread() {
public void run() {
writeLock.lock();
System.out.println(Thread.currentThread().getName() + " got the write lock");
quietSleep(3);
writeLock.unlock();
System.out.println(Thread.currentThread().getName() + " released the write lock");
};
}.start();
// a thread want to get the read lock 1s later
new Thread() {
public void run() {
quietSleep(1);
readLock.lock();
System.out.println(Thread.currentThread().getName() + " got the read lock");
};
}.start();
// 1000 threads want to get the write lock 2s later
for (int i = 0; i < 1000; i++) {
new Thread() {
public void run() {
quietSleep(2);
writeLock.lock();
System.out.println(Thread.currentThread().getName() + " got the write lock");
};
}.start();
}
}
private static void quietSleep(int seconds) {
try {
Thread.sleep(seconds * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
一开始,有一个线程拿到了写锁,并保持了3s。在此期间,一个线程想要获得读锁,然后有 1000 个线程想要获得写锁。
由于 ReentrantReadWriteLock 默认使用非公平模式,我认为写线程有很大机会获得写锁。但是我运行了很多次,每次读取线程都赢了!
输出是:
Thread-0 got the write lock
Thread-0 released the write lock
Thread-1 got the read lock
我对“不公平”的理解有误吗?
更新 根据 paxdiablo 的回答,我将代码修改为:
new Thread() {
public void run() {
quietSleep(1);
writeLock.lock();
System.out.println(Thread.currentThread().getName() + " got the write lock");
};
}.start();
for (int i = 0; i < 1000; i++) {
new Thread() {
public void run() {
quietSleep(2);
readLock.lock();
System.out.println(Thread.currentThread().getName() + " got the read lock");
};
}.start();
}
现在有一个线程想要写锁,1000 个读线程想要读锁。但输出是:
Thread-0 got the write lock
Thread-0 released the write lock
Thread-1 got the write lock
看来还是“先到先得”。
【问题讨论】:
-
仅供参考 - 在我的 Linux 机器上进行测试时,我似乎看到了这种“先到先得”的行为,但是当我们将相同的代码粘贴到 Windows 机器上时,我们确实看到了饥饿大多数时候,同一线程似乎一直在获得锁定。因此,正如 JavaDoc(和 @paxdiablo)所说,“公平”是一种相对保证,而“不公平”不是保证(可能是公平的,也可能不是)。
-
PS - 我的 Linux 机器有 4 个超线程内核(8 个并发线程),而 Windows 机器有 2 个虚拟内核(2 个并发线程)。所以这可能与它有关,因为我在 Linux 测试中可能从未有超过 8 次同时锁定尝试,但我们在 Windows 环境中肯定有超过 2 次。
标签: java reentrantreadwritelock