我研究ReentrantReadWriteLock
。
我编写简单的测试代码(我知道使用Thread.sleep()不能保证可预测的结果,但我认为我很幸运:)):
public class RWLock {
private static String val = "old";
private static ReadWriteLock lock = new ReentrantReadWriteLock();
private static long time = System.currentTimeMillis();
public void read() {
try {
lock.readLock().lock();
System.out.println("read " + val +" - "+(System.currentTimeMillis()-time));
Thread.sleep(300);
} catch (InterruptedException e) {
} finally {
lock.readLock().unlock();
}
}
public void write() {
try {
lock.writeLock().lock();
val = "new";
System.out.println("write " + val+" - "+(System.currentTimeMillis()-time));
Thread.sleep(10000);
} catch (InterruptedException e) {
} finally {
lock.writeLock().unlock();
}
}
}
class Tester {
public static void main(String[] args) throws InterruptedException {
new MyThreadRead().start();
Thread.sleep(400);
new MyThreadWrite().start();
}
}
class MyThreadRead extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
new RWLock().read();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
}
}
}
class MyThreadWrite extends Thread {
@Override
public void run() {
new RWLock().write();
}
}
输出:
read old - 0
write new - 401
read new - 10401
read new - 10902
read new - 11402
read new - 11902
read new - 12402
read new - 12902
read new - 13402
read new - 13902
read new - 14402
10401 - 401 == 10000
10000是写作的时间。
据我所知,第二次读取线程在写入之前无法完成。因此,写入和第二次读取并行执行。这对我来说不是可预测的行为。
你怎么看?
答案 0 :(得分:0)
也许你有比你意识到的更多sleep()调用。 MyThreadRead#run()和RWLock()#read()中的睡眠调用最多可达500 ms。所以,这是发生了什么。
At T=0, the reader thread grabs the read lock and sleeps for 300ms.
At T=300, the reader releases the lock, and then sleeps for another 200ms.
At T=400, the writer grabs the write lock and sleeps for ten seconds,
At T=500, the reader tries to grab the read lock, but it is blocked by the writer.
At T=10400, the writer gives up the lock, and then the reader gets to go round
its loop nine more times.
P.S。:将你的lock()调用移出try / finally语句。如,
...lock()
try {
...
} finally {
...unlock();
}
这样,如果lock()调用抛出异常,则不会调用unlock()。