java multiple writers and multiple readers locks - java

I'm trying to implement a system that follows the following constraints :
I have a shared resource, for example Atomic array
I want to support multiple reads from the array simultaneously.
I want to support multiple writes to the array simultaneously
I dont want read and write operations to happen simultaneously.
I found [this][1] stackoverflow post regarding a similar goal but I think that the solution suggested there is allowing reads simultaneously to writes :
Class ReadAndWrite {
private ReentrantLock readLock;
private ReentrantLock writeLock;
private AtomicInteger readers;
private AtomicInteger writers;
private File file;
public void write() {
if (!writeLock.isLocked()) {
readLock.tryLock();
writers.incrementAndGet(); // Increment the number of current writers
// ***** Write your stuff *****
writers.decrementAndGet(); // Decrement the number of current writers
if (readLock.isHeldByCurrentThread()) {
while(writers != 0); // Wait until all writers are finished to release the lock
readLock.unlock();
}
} else {
writeLock.lock();
write();
}
}
public void read() {
if (!readLock.isLocked()) {
writeLock.tryLock();
readers.incrementAndGet();
// ***** read your stuff *****
readers.decrementAndGet(); // Decrement the number of current read
if (writeLock.isHeldByCurrentThread()) {
while(readers != 0); // Wait until all writers are finished to release the lock
writeLock.unlock();
}
} else {
readLock.lock();
read();
}
}
As I see it, this code allows reads and writes simultaneously, for example : two threads will try to read/writer at the same time. Each one of them will enter the first if in the write/read. How can I make sure that the writes blocks the reads and reads blocks writes ?
[1]: Multiple readers and multiple writers(i mean multiple) synchronization

Rather than checking the lock repeatedly, just attempt using it:
private void writeInternal() {
//thread-unsafe writing code
}
public void write() {
if (!writeLock.tryLock()) {
writeLock.lock();
}
try {
this.writeInternal(); //in try-block to ensure unlock is called
} finally {
writeLock.unlock();
}
}
Using the readLock would be a similar approach. You also want to ensure you're truly using Read/Write locks and not just two separate locks:
private final ReadWriteLock lock;
public ReadAndWrite() {
this.lock = new ReentrantReadWriteLock();
}
Then you would access read/write locks via this.lock.readLock(), etc.

Related

Using Java threads to switch from concurrency to sequential access

I think I have a pretty simple problem, but I can't for the life of me figure it out (partly due to my inexperience with Java).
I am trying to read/write operations such that all read operations are concurrent (since the data is not modified), but write operations must be sequential.
Essentially, if I have an operations queue that looks like:
[R, R, R, W, R, R, W]
The first 3 reads will be handled concurrently,
but the first write operation will be blocked until the first 3 reads are done.
Once the first write is done, the next 2 reads are handled concurrently.
Likewise the second write operation is blocked until the 2 reads before are finished.
My problem :
I have a pool of threads that handle the Operations queue concurrently (using the take() method from LinkedBlockingQueue).
However, I don't know how to block the write operation--essentially how to wait for the threads doing read to finish.
Any help would be appreciated!
Take a look at ReentrantReadWriteLock: it provides exactly what you need. Some pseudocode:
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private void read()
{
lock.readLock().lock();
try {
...
} finally {
lock.readLock().unlock();
}
}
private void write()
{
lock.writeLock().lock();
try {
...
} finally {
lock.writeLock().unlock();
}
}
This sounds like a good case for Java's CountDownLatch. It is specifically designed for blocking until multiple threads have completed their work.
You might use it with code like the following:
final CountDownLatch allWrittenSignal = new CountDownLatch(3);
List<Runnable> writeTasks = new ArrayList<>(3);
for (int i = 0; i < 3; ++i) {
Runnable task = new Runnable() {
#Override
public void run() {
// do write work
allWrittenSignal.countDown();
}
};
writeTasks.add(task);
}
ExecutorService execSvc = Executors.newFixedThreadPool(3);
for (Runnable task : tasks) {
execSvc.execute(task);
}
allWrittenSignal.await();
// now do read work

Wait for read lock?

How can I wait for a lock before checking it?
Basically, I want to cache a list in a private variable. I only populate that list every once and a while, the other 99.999999% of the time, I want to read it, so I don't want to lock every time I read.
public class SomeServlet extends CustomServlet {
private static Object locker;
private static List<String> someList;
// moderately heavy populate, not called very often
private void populateList() {
// lock
someList.clear();
someList.addAll(getTheListStuff());
// unlock
}
public void doGetLikeMethod(HttpServletRequest req, HttpServletResponse res) {
// looking at some sort of method to check for the lock
// and wait for it, preferably with a timeout
if(!locker.isLocked(1000) && somelist.isEmpty()) {
populateList();
}
// the lock is present far less than 0.01% of the time this is checked
}
public void updateSomeList() {
populateList(); // populate list for some other reason
}
}
This is in a servlet and is not using a public framework. Our lead is very protective of adding any extra libraries, so I'd like to avoid that if at all possible. We have all the apache and java.util stuff. I'm not sure if I should use some sort of sychronized, ReadWriteLock, ReentReadWriteLock, or Lock.
I think I explained this well enough. Let me know if I need to clarify anything. I may be approaching this entirely wrong.
Use java.util.concurrent.locks.ReentrantReadWriteLock. Multiple threads can hold the read lock at a time, as long as no write is going on, so it satisfies your efficiency desires. Only a single thread can hold the write lock at a time, and only when no threads hold the read lock, so that ensures consistency between writes and reads. You probably want to set fairness on, so that write threads will eventually be able to do their writes even when there is constant contention for reads.
from http://tutorials.jenkov.com/
The rules by which a thread is allowed to lock the ReadWriteLock
either for reading or writing the guarded resource, are as follows:
Read Lock If no threads have locked the ReadWriteLock for writing,
and no thread have requested a write lock (but not yet obtained it).
Thus, multiple threads can lock the lock for reading.
Write Lock If
no threads are reading or writing. Thus, only one thread at a time
can lock the lock for writing.
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
readWriteLock.readLock().lock();
// multiple readers can enter this section
// if not locked for writing, and not writers waiting
// to lock for writing.
readWriteLock.readLock().unlock();
readWriteLock.writeLock().lock();
// only one writer can enter this section,
// and only if no threads are currently reading.
readWriteLock.writeLock().unlock();
So I think it's what you need
In the case where you are writing less and reading more you may use Copy on Write methodology.
I have re-written the code with the solution i have mentioned.
public class SomeServlet extends CustomServlet {
private volatile List<String> someList;
// moderately heavy populate, not called very often
private void populateList() {
someList = getTheListStuff();
}
public void doGetLikeMethod(HttpServletRequest req, HttpServletResponse res) {
if(someList == null) {
//If updating is expensive and do not want to do twice in worst case include the synchronization and another if check.
//If updating is not expensive ignore synchronization and nested if.
synnchroized(this){
if(someList == null) {
populateList();
}
}
}
}
public void updateSomeList() {
populateList(); // populate list for some other reason
}
}

syncronized readers and writers in java

i want to implement my own readWriteLock class, without using the readWriteLock provided by the API.
i have this situation:
public void read(){
if(!write){
read = true;
//any thread can enter here and read;
....
read = false;
}
}
public syncrhonized void write(){
if(!read){
write = true;
//only one thread at time can write.
....
write = false;
}
}
there are a lot of bad situations which can happen with this code, for example:
if one thread enter inside if(!read){...} and immediately this become true so it can't write.
if threads enter inside if(!write){...} and immediately this become true so they can't read.
i manage to use atomicBoolean, but this is a mutex - exclusion for all threads that at the same time want to read and this doesn't resolve the ambiguity.
can someone provide me an explanation?
thanks in advance.
What you are trying to do is not a good idea. As you have already mentioned yourself, there is already an existing mechanism for that. Why reinventing the wheel?
If your really need your own implementation, to do it correctly many more synchronized blocks are needed. You need to synchronize getting and releasing read lock, you cannot only synchronize access to write method.
Example which I have not checked but looks fine. All credits to Jakob Jenkov (http://tutorials.jenkov.com/java-concurrency/read-write-locks.html)
public class ReadWriteLock{
private int readers = 0;
private int writers = 0;
private int writeRequests = 0;
public synchronized void lockRead() throws InterruptedException{
while(writers > 0 || writeRequests > 0){
wait();
}
readers++;
}
public synchronized void unlockRead(){
readers--;
notifyAll();
}
public synchronized void lockWrite() throws InterruptedException{
writeRequests++;
while(readers > 0 || writers > 0){
wait();
}
writeRequests--;
writers++;
}
public synchronized void unlockWrite() throws InterruptedException{
writers--;
notifyAll();
}
}

Synchronizing a group of threads

I am writing a program in Java in where I have a HashMap<String, Deque<Integer>> info;
My data is a list of Wikipedia pages that were visited with an hour time period, along with a count of how many times each was visited.
de Florian_David_Fitz 18
de G%C3%BCnther_Jauch 1
de Gangs_of_New_York 2
de Georg_VI._(Vereinigtes_K%C3%B6nigreich) 7
de Gerry_Rafferty 2
This data gets stored in the HashMap from above with the page name as key and the Deque updated hourly with the number of visits that hour.
I want to have one thread ThreadRead that reads input files and stores the info in the HashMap. And then one ThreadCompute thread for each key in the HashMap that consumes the associated Deque.
ThreadRead needs to lock all ThreadComputes while active, then wake them up when finished so the ThreadComputes can work concurrently.
If I need a different mutex for each ThreadCompute then how can I keep all of them locked while ThreadRead works? And how can I wake up all the ThreadComputes from ThreadRead when is done?
I have used info as a lock for ThreadRead, and info.get(key) for each ThreadCompute But it is not working as I expected.
Edit:
I add some code to try to make more clear the problem. This is what I have at the moment:
HashMap<String, Deque<Integer>> info;
boolean controlCompute, control Read;
private static class ThreadRead extends Thread {
public void run() {
while(controlRead) {
try {
read();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void read() throws InterruptedException{
synchronized(info){
while(count==numThreads){
for (File file: files){
reader.parse(file, info); // Reads the file and store the data in the Hashmap
keys=true;
while(info.getSizeDeque()>10){
count=0;
info.wait();
info.notifyAll();
}
}
}
controlRead=false;
}
}
}
private static class ThreadCompute extends Thread {
public String key;
public void run() {
while(controlCompute) {
try {
compute();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void compute() throws InterruptedException{
synchronized(info.get(key)){
if(count!=numThreads){
algorithms(); //Here I apply the algorithms to the integers in the deque
if(controlRead){
info.get(key).removeFirst();
count++;
if(count==numThreads){
info.notify();
info.get(key).wait();
}
info.get(key).wait();
}
if(info.isEmptyDeque(key)){
controlCompute=false;
}
}
}
}
}
Class java.util.concurrent.locks.ReentrantReadWriteLock is good for this kind of problem. There should be exactly one instance to guard the whole HashMap. The file reader needs to acquire the write lock of the ReadWriteLock because it wants to modify the map. The other threads need to each acquire their own read lock from the one ReadWriteLock.
All your threads must be careful to limit as much as possible the scope in which they hold their locks, so in particular, the file-read thread should acquire the write lock immediately before modifying the map, hold it until all modifications for one entry are complete, then release it. The other threads don't block each other, so they could in principle hold their locks longer, but doing so will block the file reader.

Read Write File Through Multiple threads

I want to read and write in a same file through threads.
But the condition is when the first thread finishes reading only then the other thread should write.
The solution that I proposed was:
class XYX {
public void read(){
synchronised(fileObj){
//write the reading logic
}
}
public void write(){
synchronised(fileObj){
//write the writing logic
}
}
}
Please let me know your ideas
I want to retain this Ordering
Reading - Writing - Reading - Writing - Reading - so on
I would use a Lock shared between the threads.
Since only one thread would hold the lock at any given time, you would make sure that the writing thread would only write to the file when the reading thread had released the lock (on a finally block!)
I would use two semaphores one for read, one for write, with only one unit between them. The read method waits on the read semaphore, then reads, then signals the write semaphore. The writer waits on the write semaphore, then writes, then signals the read semaphore.
Definitely use something from java.util.concurrent. I'd suggest two CountDownLatches here. Writing happens in one thread before calling cdl1.countDown and cdl2.await; the reading thread does the opposite.
If a total ordering of read-then-write must be maintained then it's easiest to use a monitor:
class XYX {
private final Object fileObj = new Object();
private volatile boolean writerWaits = true;
public void read(){
// read from file
synchronized(fileObj){
writerWaits = false;
fileObj.notify(); // signal the writer to begin
}
}
public void write(){
synchronized(fileObj){
while(writerWaits)
fileObject.wait(); // wait for signal from reader
}
// write to file
}
}

Categories

Resources