ReentrantReadWriteLock читает, пока writeLock заблокирован?
Я исследую 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 это время написания.
Как я понял, вторая прочитанная ветка не может закончиться перед записью. Таким образом, запись и второе чтение выполняется параллельно. Это не предсказуемое поведение для меня.
Что вы думаете об этом?
1 ответ
Решение
Возможно, у вас больше вызовов sleep (), чем вы думаете. Спящие вызовы в MyThreadRead#run() и в RWLock()#read() составляют до 500 мс. Итак, вот что происходит.
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.
PS: уберите вызовы lock () из операторов try/finally. Например,
...lock()
try {
...
} finally {
...unlock();
}
Таким образом, если вызов lock () выдает исключение, unlock () вызываться не будет.