Read Write File Through Multiple threads - java

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
}
}

Related

java multiple writers and multiple readers locks

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.

file thread synchronization

How to perform read and write operation by using thread synchronization.
Condition: If one file exists where writers may write information to, only one writer may write at a time. Confusion may arise if a reader is trying read at the same as a writer is writing. Since readers only look at the data, but do not modify the data, we can allow more than one reader to read at the same time.
//reader thread
class Read extends Thread {
static File Reader fr1 = null;
static Buffered Reader br1 = null;
static synchronized void reader() throws IO Exception {
String path ="C:/Users/teja/Documents/file1.txt";
fr1 = new File Reader(path);
br1 = new Buffered Reader(fr);
int i;
while ((i = br. read()) != -1)
System .out. print((char) i);
System .out. print ln();
}
public void run() {
try {
reader();
} catch (IO Exception e) {
e. print Stack Trace();
}
}
}
//writer code
class Writer extends Thread {
static Buffered Writer bw1 = null;
static File Writer fw1 = null;
static synchronized void writer() throws IO Exception {
Scanner scanner = new Scanner(System.in);
System .out .print ln("enter data to be added:");
String data = scanner. nextLine();
String path = "C:/Users/vt/Documents/file1.txt";
fw1 = new File Writer(path, true);
bw1 = new Buffered Writer(fw1);
bw1.newLine();
bw1.write(data);
bw1.flush();
scanner. close();
System. out . println("data added");
}
public void run() {
try {
writer();
} catch (IO Exception e) {
e. print Stack Trace();
}
}
}
//main method
public class File Read Write {
public static void main(String[] args) {
Read rd1 =new Read();
Read rd2=new Read();
Writer wt1=new Writer();
rd1.run();
rd2.run();
wt1.run();
rd1. run();
}
}
I am new to files and threading in java. I know this is not correct approach. Guide me.
If one file exists where writers may write information to, only one writer may write at a time. Confusion may arise if a reader is trying read at the same as a writer is writing. Since readers only look at the data, but do not modify the data, we can allow more than one reader to read at the same time.
There are two approaches to this.
(1) Either lock the resource and have the readers wait until the writer has completed the writing operation (or likewise, have a writer waits until all readers are done). This approach guarantees consistency, but can be slow if a lot of writers/readers are working on the resource at the same time (see Lock in java.util.concurrent.locks package).
(2) Keep an in-memory-version of the contents of the file that is served to readers only. When a change is made, this in-memory version is updated. Here, you'll have more speed, but you lose consistency and you'll need more memory.
The condition you want to avoid is generally referred as race condition and what you want to avoid it is a synchronization method between threads. There are more choices available but the most suitable for your case are mutex and read-write lock.
A mutex basically just lock the resource before any operation on the shared resource is performed, independently from the type of operation and free it after the operation is terminated. So a read will block the resource and any other operation, read or write will be blocked.
A write will block the resource too so again no other read or write operation can be performed before the action is terminated and mutex unlocked. So basically a mutex has 2 states: locked and unlocked.
read-write lock gives you more freedom based on the fact that read only operations do not result in inconsistencies. A read-write lock has 3 states: unlocked, read lock, write lock. A write lock works as a regular mutex blocking any other operation. A read lock on the contrary blocks only write operations.
I am not a Java expert but from this answer mutex in Java can be used as the following:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
private final Lock lock = new ReentrantLock(true);
lock.lock()
/*open file and do stuff*/
try {
// do something
} catch (Exception e) {
// handle the exception
} finally {
lock.unlock();
}
Instead here you can find a description of a read-write lock class.
From the implementation point of view you can create an instance of one of the two synchronization method and have your read/write thread instances keeping a reference to it, as an instance variable.

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
}
}

Java ReentrantLock and Condition | producers finish work, consumer gets stuck

General Information:
Three reader-threads read randomly from a file in chunks where each chunk has an ID and they write to a normal ArrayList. A writer-thread writes to an outputfile as soon as a chunk with the needed ID is added to the list.
For that reason I have written a BlockingChunkList which should synchronize the add() and getNextChunk() methods.
It works for me with synchronized + notify + notifyAll in one case and with a synchronized list in another.
I don't manage to do it when I use ReentrantLock and Condition. The writer-thread only writes four chunks and then he gets stuck.
Why it might not work:
I have the suspicion that once the readers are done the writer doesn't get the lock back. However i would expect that everytime when there is something to write (available=true) then the writer thread should be called. They seem to ignore hasAccess.await() when available is true.
How it should work:
The reading threads only call the add method and they release the writing thread only when there is something to write (available). They also block themselves when available=true. This lock is released when the writer has written something by calling hasAccess.signalAll()
The writing thread only calls the getNextChunk() method and he releases the other threads when he wrote the chunk. He blocks himself when available=false and he is released by the readers.
Question:
The reading threads finish their work and the writing thread only writes the first 4 chunks. I expect that the writer is always called when available=true.
I don't need an exact solution, a hint is appreciated as well since I think I am missing something. So: What am I missing ?
Thank You
EDIT: Concurrency is handeled only in the posted class. The main-method only starts the treads.
EDIT 2: This is one of my first shots at concurrency. I know that ArrayList is not thread safe. I would like to make it so by using ReentrantLock and Condition in order to understand the concepts. The BASIC idea is to block either reader or writer whether available is true or false.
import java.util.ArrayList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class BlockingChunkQueue {
private final ArrayList<Chunk> chunks;
private volatile int currentID = 0; // first ID for which the writer needs to wait
private volatile boolean available; // true if the ID is in the list
private final Lock listLock;
private final Condition hasAccess;
public BlockingChunkQueue(){
chunks = new ArrayList<>();
listLock = new ReentrantLock();
hasAccess = listLock.newCondition();
available = false;
}
/*
* While there is a chunk which might be written to the output (=correct ID) then wait for access.
* Then add the chunk and if the added chunk has the ID for which the other thread is waiting, then,
* then available = true and signal the waiting thread.
*
*
*/
public void add(Chunk chunk) throws InterruptedException{
listLock.lock();
try{
while(available){
hasAccess.await(); // reader block yourself until you get the lock back
}
chunks.add(chunk);
if(chunk.getId() == currentID){
available = true;
hasAccess.signalAll();
}
}finally{
listLock.unlock();
}
}
/*
* If the chunk is not available then wait.
* If it becomes available then increment the ID, remove it from the list, signal the reader-threads and set available false.
* return the chunk which will be written to the output.
*/
public Chunk getNextChunk() throws InterruptedException {
listLock.lock();
try{
while(!available){
hasAccess.await(); // block yourself until u can write something
}
for(Chunk c : chunks){
if(c.getId() == currentID){
currentID++;
chunks.remove(c);
hasAccess.signalAll(); //signal the readers
available = false;
return c;
}
}
}finally{
listLock.unlock();
}
return null;
}
public int getcurrentID(){ return currentID;}
public boolean isEmpty(){ return chunks.isEmpty(); }
public int size(){return chunks.size();}
}
SOLUTION:
There was nothing wrong with handling the threads. It turned out to be a logical error from my side. The writing thread gets stuck because he doesn't get the chance to check for the necessary IDs because the writers read the chunks randomly. Thanks for the helpfull answer.
There are a several of problems here.
What is the purpose of the volatile variable available which is only read or mutated while the lock is held?
The isEmtpy and size methods call methods on chunks without holding the lock. ArrayList is not thread-safe. The behavior of these calls cannot be predicted.
A reason you might get stuck is if multiple chunks get added before getNextChunk is called.
In your loop to find the "current" you set available to false, but it may actually already be in the list:
for(Chunk c : chunks){
if(c.getId() == currentID){
currentID++;
chunks.remove(c);
hasAccess.signalAll(); //signal the readers
available = false;
return c;
}
}
Consider storing your chunks in a Map<Integer,Chunk> so that can easily see if a chunk is present by the identifier.

Java - How To Synchronize 2 Threads On 1 List?

How can I synchronize 2 threads to handle data in a list ?
thread A is adding / changing items in a list (writing to the list)
thread B is displaying the items (only reading the list)
I would like to "notify" thread B when it can display the list. In the time of reading the list it must not be changed by thread A. When thread B is done reading, thread A can start changing the list again.
My guesses go to
synchronized(obj)
list.wait() + list.notify()
Threads aren't invoking each other. They run concurrent all the time.
You could put all changes in Runnables and put them in a queue that Thread A executes in order. After each job, A must generate a snapshot of the modified list and submit it to Thread B. You could use Executors for that.
General concept (as I see it in your case) would be as follows.
1) Create an instance of List that you're planning to work with.
2) Write 2 classes corresponding to your thread A and thread B that both implement Runnable and take List as their constructor parameter.
3) Synchronize these 2 classes on list instance:
// method in class that adds
public void add() {
synchronized(list) {
// perform addition ...
list.notify();
}
}
// method in class that reads
public void read() throws InterruptedException {
synchronized(list) {
while (list.isEmpty())
list.wait();
// process data ...
}
}
4) Create 2 threads with argumens corresponding to instances of these 2 classes and start them.
Reader and writer locks are your friends here.
•thread A is adding / changing items in a list (writing to the list)
... so it can use the write lock ...
•thread B is displaying the items (only reading the list)
... so it can use the read lock.
Let's assume that you're using something straight forward for your wait/notify (for example, the built-in Object methods) to block the read and display thread. At that point, your code looks something like this:
/** This is the read/write lock that both threads can see */
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
/** This method is called by thread A (the writer / modifier) */
public void add() {
try {
// Only one writer at a time allowed
lock.writeLock().lock();
// Insert code here: Add to the list
} finally {
// Unlock in the finally block to ensure that lock is released
lock.writeLock().unlock();
}
// Notify anyone who's waiting for data
list.notify();
}
/** This method is called by thread B (the reader / displayer) */
public void read() throws InterruptedException {
try {
// As many readers as you like at a time
lock.readLock().lock();
// Insert code here: read from the list
} finally {
// Unlock in the finally block to ensure that lock is released
lock.readLock().unlock();
}
// Wait for new data
list.wait();
}
To make things even more convenient, you can get rid of the notify/wait messaging by using a blocking data structure: e.g., one of the BlockingQueues. In that case, you don't write any notification at all. The reader blocks waiting for new data. When the writer adds data to the queue, the reader unblocks, drains the new data to process, does its thing and then blocks again.
I tried concurrency packages suggested here or here and it works well. The threads lock each other out:
final Lock lock = new ReentrantLock(true);
// thread A
lock.lock();
// write to list
lock.unlock();
// thread B
lock.lock();
// read from list
lock.unlock();
Not sure if they can execute precisely one after another and I didn't get the notify feature. But that doesn't hurt my application.

Categories

Resources