Reputation: 1
I have an issue with the Writer thread being starved without getting a lock.
Please have a look at the following code. If I am trying to get the lock using tryLock()
for the read lock, the writer process will become starved and it will never be able to write. Even with the fairness the writer process will completely get starved and will never execute. Instead if I try just the reader.readLock()
then the writer process will be able to get the lock.
Please do let me know if I am missing something, The writer process thread even if it set to high priority it never gets hold of the lock and will get stuck waiting for the lock.
Can anyone please tell me whether I can use trylock()
with ReadWriteLocks
.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.*;
class ReadWrite{
private int a, j=0,k =0;
private final ReentrantReadWriteLock asd = new ReentrantReadWriteLock();
private final Lock readlock = asd.readLock();
private final Lock writelock = asd.writeLock();
ReadWrite(){
a = 0 ;
}
ReadWrite(int a){
this.a = a;
}
public int read() {
try {
if (readlock.tryLock())
{
//readlock.lock();
k = k + 1;
if (k%100000==0) {
System.out.println("read " + k + " times ==> Written " + j + " times");
}
readlock.unlock();
return a;
}
}
catch(Exception E) {
System.out.println(E);
return a;
}
return 0;
}
public void write(int a) {
int k = 9;
try {
writelock.lock();
//writelock.lock();
this.a = a;
k = 0;
j = j + 1;
System.out.println("Acquored");
}
catch(Exception E) {
System.out.println(E);
}
finally {
if (k == 0 )
writelock.unlock();
}
}
}
class reader implements Runnable{
ReadWrite a;
reader(Object b){
a = (ReadWrite) b;
}
public void run() {
while(true) {
try{a.read();
//Thread.sleep(100);
}
catch(Exception E) {
}
}
}
}
class writer implements Runnable{
ReadWrite a;
writer(Object b){
a = (ReadWrite) b;
}
public void run() {
//Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
while(true) {
try {
//Thread.sleep(1);
}
catch(Exception E) {
}
a.write((int) Math.ceil(Math.random()*100));
}
}
}
class Practice{
public static void main(String args[]) {
ReadWrite a = new ReadWrite();
System.out.println("Invoking Write Thread");
ExecutorService asd = Executors.newFixedThreadPool(100);
asd.execute(new writer(a));
for (int i = 0 ; i < 98 ; i ++)
asd.execute(new reader(a));
}
}
Upvotes: 0
Views: 584
Reputation: 11280
Using the ReentrantReadWriteLock
in this scenario without fairness, will never work : too many reader threads will simply starve the writer thread.
With fairness the writer thread will get the occasional chance to write.
However, setting the ReentrantReadWriteLock
to fair in your code proved to be fruitless. Here's the sting : your readers don't use lock()
, but tryLock()
. As such they are never queued for lock acquisition, they just get it if it's available. And by not queueing (internally in ReentrantReadWriteLock
) they circumvent the fairness policy.
Note the javadoc on tryLock()
for the ReadLock
object :
Acquires the read lock only if the write lock is not held by another thread at the time of invocation. Acquires the read lock if the write lock is not held by another thread and returns immediately with the value true. Even when this lock has been set to use a fair ordering policy, a call to tryLock() will immediately acquire the read lock if it is available, whether or not other threads are currently waiting for the read lock. This "barging" behavior can be useful in certain circumstances, even though it breaks fairness. If you want to honor the fairness setting for this lock, then use tryLock(0, TimeUnit.SECONDS) which is almost equivalent (it also detects interruption).
If the write lock is held by another thread then this method will return immediately with the value false.
(emphasis mine)
Upvotes: 2