I've read java doc: ReentrantReadWriteLock
And I don't see that writeLock has any priority over readLock
But also I've read topics like this: Are read and write locks in ReentrantReadWriteLock somehow related?
and I see there in both answers following phrases:
if lock is held by readers and thread request write lock no more readers are allowed to acquire read lock until thread which has acquired write lock release it.
Prefers writers over readers. That is, if a writer is waiting on the lock, no new readers from other thread are allowed to access the resource. Existing readers can continue to use the resource until they release the lock. This prevents so-called "writer starvation".
And these phrases sounds meaningfully and looks like I've already read it somewhere else.
But obviously it is a contradiction with java doc.
Was it changed in latest JDK ? is it still valid ?
How to prevent writer starvation ?
ReentrantReadWriteLock describes two modes of operation: fair mode and non-fair mode. The selections that you cited appear to be aiming to describe fair mode. I wouldn't say that either are obviously contradictory. However, I can see where imprecise wording in the first one ("no more readers are allowed") could lead to confusion. I suspect that "more readers" was intended to refer to new readers from other threads, not additional reentrant reads from the same thread, which some might interpret to be the same reader. If interpreted in this way, then they seem consistent with the JavaDoc.
I've created sample to check:
public class RWLockTest {
public static final Logger LOGGER = LoggerFactory.getLogger(RWLockTest.class);
public static void main(String[] args) {
SomeClass someClass = new SomeClass();
Reader readerRunnable = new Reader(someClass);
Writer writerRunnable = new Writer(someClass);
//group 1 readers
for (int i = 0; i < 10; i++) {
new Thread(readerRunnable).start();
}
// 2 writers
new Thread(writerRunnable).start();
LOGGER.info("!!!!!!!!!!!!!!!WRITER_1 WAS STARTED!!!!!!!!!!!!!!!");
new Thread(writerRunnable).start();
LOGGER.info("!!!!!!!!!!!!!!!WRITER_2 WAS STARTED!!!!!!!!!!!!!!!");
//group 2 readers
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(readerRunnable);
LOGGER.info(String.format("%s was submitted", thread.getId()));
thread.start();
}
}
public static class SomeClass {
public ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void read() {
readWriteLock.readLock().lock();
try {
LOGGER.info(String.format("Read by %s started", Thread.currentThread().getId()));
Thread.sleep(5000);
LOGGER.info(String.format("Read by %s finished", Thread.currentThread().getId()));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readWriteLock.readLock().unlock();
}
}
public void write() {
readWriteLock.writeLock().lock();
try {
LOGGER.info(String.format("!!!!!!!!!!Write by %s started!!!!!!!!!!!!", Thread.currentThread().getId()));
Thread.sleep(3000);
LOGGER.info(String.format("!!!!!!!!!!Write by %s finished!!!!!!!!", Thread.currentThread().getId()));
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readWriteLock.writeLock().unlock();
}
}
}
public static class Reader implements Runnable {
SomeClass someClass;
public Reader(SomeClass someClass) {
this.someClass = someClass;
}
@Override
public void run() {
someClass.read();
}
}
public static class Writer implements Runnable {
SomeClass someClass;
public Writer(SomeClass someClass) {
this.someClass = someClass;
}
@Override
public void run() {
someClass.write();
}
}
}
I tried to run a lot of time and output is typically like this:
16:31:49.037 [main] INFO my.pack.RWLockTest - !!!!!!!!!!!!!!!WRITER_1 WAS STARTED!!!!!!!!!!!!!!!
16:31:49.040 [main] INFO my.pack.RWLockTest - !!!!!!!!!!!!!!!WRITER_2 WAS STARTED!!!!!!!!!!!!!!!
16:31:49.046 [Thread-1] INFO my.pack.RWLockTest - Read by 13 started
16:31:49.046 [main] INFO my.pack.RWLockTest - 24 was submitted
16:31:49.046 [Thread-7] INFO my.pack.RWLockTest - Read by 19 started
16:31:49.046 [Thread-4] INFO my.pack.RWLockTest - Read by 16 started
16:31:49.046 [Thread-5] INFO my.pack.RWLockTest - Read by 17 started
16:31:49.046 [Thread-0] INFO my.pack.RWLockTest - Read by 12 started
16:31:49.046 [Thread-3] INFO my.pack.RWLockTest - Read by 15 started
16:31:49.047 [main] INFO my.pack.RWLockTest - 25 was submitted
16:31:49.046 [Thread-9] INFO my.pack.RWLockTest - Read by 21 started
16:31:49.047 [Thread-8] INFO my.pack.RWLockTest - Read by 20 started
16:31:49.047 [main] INFO my.pack.RWLockTest - 26 was submitted
16:31:49.047 [Thread-2] INFO my.pack.RWLockTest - Read by 14 started
16:31:49.047 [Thread-6] INFO my.pack.RWLockTest - Read by 18 started
16:31:49.047 [main] INFO my.pack.RWLockTest - 27 was submitted
16:31:49.048 [main] INFO my.pack.RWLockTest - 28 was submitted
16:31:49.048 [main] INFO my.pack.RWLockTest - 29 was submitted
16:31:49.048 [main] INFO my.pack.RWLockTest - 30 was submitted
16:31:49.048 [main] INFO my.pack.RWLockTest - 31 was submitted
16:31:49.049 [main] INFO my.pack.RWLockTest - 32 was submitted
16:31:49.049 [main] INFO my.pack.RWLockTest - 33 was submitted
16:31:54.047 [Thread-7] INFO my.pack.RWLockTest - Read by 19 finished
16:31:54.048 [Thread-6] INFO my.pack.RWLockTest - Read by 18 finished
16:31:54.047 [Thread-5] INFO my.pack.RWLockTest - Read by 17 finished
16:31:54.049 [Thread-2] INFO my.pack.RWLockTest - Read by 14 finished
16:31:54.051 [Thread-8] INFO my.pack.RWLockTest - Read by 20 finished
16:31:54.047 [Thread-1] INFO my.pack.RWLockTest - Read by 13 finished
16:31:54.050 [Thread-9] INFO my.pack.RWLockTest - Read by 21 finished
16:31:54.049 [Thread-4] INFO my.pack.RWLockTest - Read by 16 finished
16:31:54.049 [Thread-3] INFO my.pack.RWLockTest - Read by 15 finished
16:31:54.049 [Thread-0] INFO my.pack.RWLockTest - Read by 12 finished
16:31:54.057 [Thread-10] INFO my.pack.RWLockTest - !!!!!!!!!!Write by 22 started!!!!!!!!!!!!
16:31:57.057 [Thread-10] INFO my.pack.RWLockTest - !!!!!!!!!!Write by 22 finished!!!!!!!!
16:31:57.058 [Thread-11] INFO my.pack.RWLockTest - !!!!!!!!!!Write by 23 started!!!!!!!!!!!!
16:32:00.060 [Thread-11] INFO my.pack.RWLockTest - !!!!!!!!!!Write by 23 finished!!!!!!!!
16:32:00.061 [Thread-13] INFO my.pack.RWLockTest - Read by 25 started
16:32:00.061 [Thread-14] INFO my.pack.RWLockTest - Read by 26 started
16:32:00.061 [Thread-12] INFO my.pack.RWLockTest - Read by 24 started
16:32:00.061 [Thread-15] INFO my.pack.RWLockTest - Read by 27 started
16:32:00.061 [Thread-17] INFO my.pack.RWLockTest - Read by 29 started
16:32:00.062 [Thread-19] INFO my.pack.RWLockTest - Read by 31 started
16:32:00.062 [Thread-18] INFO my.pack.RWLockTest - Read by 30 started
16:32:00.061 [Thread-16] INFO my.pack.RWLockTest - Read by 28 started
16:32:00.062 [Thread-20] INFO my.pack.RWLockTest - Read by 32 started
16:32:00.062 [Thread-21] INFO my.pack.RWLockTest - Read by 33 started
16:32:05.060 [Thread-12] INFO my.pack.RWLockTest - Read by 24 finished
16:32:05.060 [Thread-15] INFO my.pack.RWLockTest - Read by 27 finished
16:32:05.060 [Thread-13] INFO my.pack.RWLockTest - Read by 25 finished
16:32:05.060 [Thread-17] INFO my.pack.RWLockTest - Read by 29 finished
16:32:05.060 [Thread-14] INFO my.pack.RWLockTest - Read by 26 finished
16:32:05.062 [Thread-21] INFO my.pack.RWLockTest - Read by 33 finished
16:32:05.062 [Thread-16] INFO my.pack.RWLockTest - Read by 28 finished
16:32:05.062 [Thread-19] INFO my.pack.RWLockTest - Read by 31 finished
16:32:05.062 [Thread-18] INFO my.pack.RWLockTest - Read by 30 finished
16:32:05.062 [Thread-20] INFO my.pack.RWLockTest - Read by 32 finished
What does it mean?
As you can see I do following:
As you can see the delay between the first write was submitted(16:31:49.037 [main] INFO my.pack.RWLockTest - !!!!!!!!!!!!!!!WRITER_1 WAS STARTED!!!!!!!!!!!!!!!) and when the it actually stated((acquired lock)16:31:54.057 [Thread-10] INFO my.pack.RWLockTest - !!!!!!!!!!Write by 22 started!!!!!!!!!!!!) is 5 sec. It is a time of read.
Also you can see that after 2 writers thread were submitted we submitted 10 readers threads with ids from 24 to 33 and all of them were actually started(acquired locks) after writer thread finished their works.
So readers threads with ids from 24 to 33 were submitted at 16:31:49 and at this time readlock was acquired by first 10 readers and looks like they were able to acquire readlock too but looks like there are something inside ReentrantReadWriteLock that prevents it to avoid writer starvation. Eventually the second group of readers were able to acquire lock only at 16:32:00(6 sec after submitting)
I don't know if it is guaranteed but from my tests it always works in a such way. So we have some priority of Writers over Readers although java doc says:
This class does not impose a reader or writer preference ordering for lock access
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With