I am new in multithreading and i am confused , why read lock is needed in java synchronization .Also i understand the use case of write lock.In which scenario we need to limit the reader access for threads.
Suppose we don't have read lock in java , then what's the problem.
Suppose there is shared resource R. A thread T1 is reading it and it's not locked as there is no read lock in java(As you said)meanwhile a second thread try to access the R1 to write on it. As there in no information attached to the R1 that a thread is currently read it , Second thread will get the write lock and start writing to it and is unexpected. Read lock is the extra information attached to resource that tell the later threads that resource already in access for reading , wait for write access or you can access only for read.
Read lock can be access by multiple thread.
From Java 11 docs
The read lock may be held simultaneously by multiple reader threads,
so long as there are no writers. The write lock is exclusive.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed last month.
Improve this question
While a write lock is being held, Read lock can be acquired. But not vice versa. What is the rationale for this design choice.
public static void main(String[] args)
{
System.out.println("read to write test");
ReadWriteLock lock = new ReentrantReadWriteLock();
lock.writeLock().lock();
lock.readLock().lock();
System.out.println("Read locks can be acquired after Write locks are acquired as well.");
}
Output of above code:
read to write test
Read locks can be acquired after Write locks are acquired as well.
Vice versa doesn't work.
public static void main(String[] args) throws InterruptedException {
ReadWriteLock lock = new ReentrantReadWriteLock();
lock.readLock().lock();
System.out.println("Read lock is acquired");
System.out.print("Trying to get write lock. ");
boolean writeLockAcquired = lock.writeLock().tryLock(120, TimeUnit.SECONDS);
if (! writeLockAcquired){
System.out.println("Even after 120 seconds, we couldn't get write lock");
}
else{
System.out.println("We could get write lock.");
}
}
Here is the output:
Read lock is acquired
Trying to get write lock. Even after 120 seconds, we couldn't get write lock
Can some one point to snippets in Java open source projects to look at practical usage of Read Write locks. I understand that there are a lot of Java open source projects like ElasticSearch / Hadoop / Spark etc.
While a write lock is being held, Read lock can be acquired.
Locking is to protect against access by concurrent threads.
A read-write lock allows multiple concurrent readers OR a single writer thread.
If a thread owns the write lock, it already has exclusive access, so there's no harm in granting it read access. It will not conflict with itself.
If a thread owns the read lock, there is no guarantee it has exclusive access, so granting the write lock is disallowed. There is no benefit in special-casing the 'single thread wanting both locks' situation.
In other systems, the lock modes are referred to as 'exclusive' (= write) and 'shared' (= read) modes. Considering those terms might help clarify the situation.
There is further rationale in the documentation for the reentrant read-write lock:
Additionally, a writer can acquire the read lock, but not vice-versa.
Among other applications, reentrancy can be useful when write locks
are held during calls or callbacks to methods that perform reads under
read locks. If a reader tries to acquire the write lock it will never
succeed.
Allowing a read lock to be upgraded to a write lock would be a source of deadlocks:
Thread A takes a read lock (now no one can take a write lock)
Thread B takes a read lock
Thread A decides to upgrade to a write lock -- blocks
Thread B decides to upgrade to a write lock -- deadlock
The correct way to do this (when you are doing an operation which may need a write lock, but usually doesn't) is to retry it:
Thread A takes a read lock
Thread B takes a read lock
Thread A decides it needs a write lock
Thread A drops the read lock
Thread A tries to take the write lock -- blocks because B currently holds the read lock
Thread B decides it needs a write lock
Thread B drops the read lock
Thread A gets the write lock
Thread B tries to take the write lock and blocks
Thread A finishes its work and releases the lock
Thread B takes the write lock
In ReentrantReadWriteLock documentation it is said:
writer can acquire the read lock, but not vice-versa
If I understand correctly it means that from the same thread you can execute:
//thread1
lock.writeLock().lock()
lock.readLock().lock()
print("this line executes")
This makes sense: if you already locked write no other thread can enter the locked code. But if you locked read, why can't you enter the write block in the same thread if no other thread make read lock? So this doesn't work:
//thread1
lock.readLock().lock()
lock.writeLock().lock()
print("this line doesn't execute")
Why do you have to unlock the read before locking write in the same thread?
ReentrantReadWriteLock doesn't mean that the normal rules locking are not followed.
If a thread acquired a lock for reading purpose, it expects the value of the target data not to change for the duration of the lock. Having otherwise would prevent repeatable-reads. Conceptually, if you let a thread (the same or another) acquire a write lock when a read lock is out, you are breaching that rule.
If a thread acquired a lock for writing, it implicitly has reading rights as well, so acquisition of a read-lock can be granted because it doesn't really breach the contract of the lock (if I can write, I can read) nor the expectations of the lock holder (I locked for writing so I am the only one that can read or write now).
I don't actually know the answer, but it may be to help you avoid writing code that can deadlock.
Suppose you have two threads that execute the same code. Both threads have acquired a read lock. Then, both threads attempt to acquire the write lock. Neither thread will be able to proceed until the other thread releases its read lock, but neither thread will release it's read lock while it's waiting to upgrade.
A different implementation could detect the deadlock, and throw exceptions in both threads when it is discovered, but maybe someone thought that would either (A) adversely impact the performance for applications that do not require deadlock detection, or (B) complicate the API too much.
By disallowing you to upgrade a read lock to a write lock, they've made it impossible for you to write a program that deadlocks in that particular way.
What I know is:
ReadLock and WriteLock affect each other somehow
WriteLock is just like synchronized
ReadLock seems cannot work alone
readLock.lock();
This means that if any other thread is writing (i.e. holds a
write lock) then stop here until no other thread is writing.
Once the lock is granted no other thread will be allowed to write
(i.e. take a write lock) until the lock is released.
writeLock.lock();
This means that if any other thread is reading or writing, stop
here and wait until no other thread is reading or writing.
Once the lock is granted, no other thread will be allowed to read
or write (i.e. take a read or write lock) until the lock is released.
Combining these you can arrange for only one thread at a time to have write access, but as many readers as you like can read at the same time except when a thread is writing.
Put another way. Every time you want to read from the structure, take a read lock. Every time you want to write, take a write lock. This way whenever a write happens no-one is reading (you can imagine you have exclusive access), but there can be many readers reading at the same time so long as no-one is writing.
The documentation for ReadWriteLock makes this clear:
A ReadWriteLock maintains a pair of associated locks, one for read-only operations and one for writing. The read lock may be held simultaneously by multiple reader threads, so long as there are no writers. The write lock is exclusive.
So you can have many readers at a time, but only one writer - and the writer will prevent readers from reading, too. This is useful if you've got some resource which is safe to read from multiple threads, and where reading is much more common than writing, but when the resource is not actually read-only. (If there are no writers and reading is safe, there's no need for a lock at all.)
When a thread acquires a WriteLock, no other thread can acquire the ReadLock nor the WriteLock of the same instance of ReentrantReadWriteLock, unless that thread releases the lock. However, multiple threads can acquire the ReadLock at the same time.
Using ReadWriteLock, you can improve performance of an application in which more reads are performed on a shared object than writes.
ReadWriteLock maintains two locks for read and write operations. Only one lock either read or write can be acquired at the same time. But multiple threads can simultaneously acquire read lock provided write lock is not acquired by any thread.
ReentrantReadWriteLock is an implementation of ReadWriteLock. It gives write lock to the longest waiting thread if multiple thread are not waiting for read lock. If multiple threads are waiting for read lock, read lock is granted to them.
A reader which acquired read lock can reacquire read lock, similarly, writer can reacquire write lock and can acquire read lock also.
See http://www.zoftino.com/java-concurrency-lock-and-condition-examples
Consider a situation: In a case when data structures are read-mostly - they are mutable and are sometimes modified, but most accesses involve mostly reading, so in these case we can relax the locking mechanism in away that we can allow multiple readers to access the data structures instead of readers waiting while one reader has released the lock. As long as each thread is guaranteed an up to date view of the shared data and no thread modifies it while the readers are viewing it, there will no problems. This is what read write allows : a resource can be accessed by multiple readers or a single writer at a time, but not both.
If a thread has lock on any object, can read methods still work ?
If I have object with various 'get' methods than can I use the object to do print outs while some other thread has lock on it ? I am working on project where object has various properties, which I need to print it out periodically. However, there are other threads running which may gain lock to write those properties. I am using Semaphore for synchronization. Also, I will be doing more reading than writing. What is the best approach to tackle these situation ?
I believe ReentrantReadWriteLock (Java 5+) is just made for your requirements.
We have a multi threaded java program. Multiple-threads will write to a file, and one thread will read from that file. I am looking for some design ideas. Is synchronization necessary?
FileChannel is in theory thread safe. From the javadoc:
File channels are safe for use by multiple concurrent threads. The
close method may be invoked at any time, as specified by the Channel
interface. Only one operation that involves the channel's position or
can change its file's size may be in progress at any given time;
attempts to initiate a second such operation while the first is still
in progress will block until the first operation completes. Other
operations, in particular those that take an explicit position, may
proceed concurrently; whether they in fact do so is dependent upon the
underlying implementation and is therefore unspecified.
If you can use these, then you can use the built-in synchronization, rather than having to write your own.
I would consider synchronization in this case. Imagine that 2 threads (t1 and t2) open the file at the same time and start writing to it. The changes performed by the first thread are overwrited by the second thread because the second thread is the last to save the changes to the file. When a thread t1 is writing to the file, t2 must wait until t1 finishes it's task before it can open it.
Also, if you care about the latest possible update of the file, you should synchronize the writing threads with the thread that reads the file so that if there's any thread writing the the file, the reading thread should wait.
If being synchronous isn't important, you could have your writer running in its own thread, and allow other threads to queue up writes to the file. Although I think the first thing to consider is whether writing to a file is really what you want to do. Especially in high-traffic situations, having a lot of disk I/O may not be very efficient.
If you wanted multiple readers and one writer, you would be looking for a Read Write Lock or a Read Write Mutex.
But you want multiple writers and one reader. How do you know these writers won't overwrite each others data? Are they somehow segregated?
Once multiple Threads access shared data then Synchronization is necessary. If multiple threads write to the same file without some form of locking, then potentially you will end up with a lost update problem.
Reading is not as big an issue in all circumstances so you need to consider...if a thread is reading the file and at the same time another thread updates the file, does the reading thread need to know about the change? If so you need to lock the file for the reading thread also.
You need synchronization (locking) if you have a mix of readers and writers or writers and writers. If you only have readers, you don't need any synchronization.
You don't want two processes writing to the same file or one process writing a file that another is reading.
Synchronization is necessary in this case. FileChannel is useful for preventing files being modified by processes outside the JVM: not so for applications which include multiple threads writing to a single file.
From (further down in) the JavaDoc for FileChannel:
File locks are held on behalf of the
entire Java virtual machine. They are
not suitable for controlling access to
a file by multiple threads within the
same virtual machine.
See this post for a brief discussion of strategies to share file writing between threads.