JAVA READERS / WRITERS PROBLEM Assume there are multiple readers that want to re
ID: 3764520 • Letter: J
Question
JAVA READERS / WRITERS PROBLEM
Assume there are multiple readers that want to read from a database and also, there are multiple writers that want to update the database. While many readers can read from the database at the same time, but when a writer is updating the database, no other writer and any reader should be allowed to access the database. That is, basically it is concurrent readers and mutually exclusive writer problem. This is also known as Readers/Writers problem.
Your task is to implement the Readers/Writers problem using monitorssatisfying the following constraints:
Any number of readers can read concurrently. Writers cannot execute concurrently.
While any writer is waiting, no more than 3 readers will get chance to execute their read operations before any writer is allowed to write.
If any reader is waiting, no more than 2 writers will get chance to execute their write operations before any reader is allowed to execute its read operation.
if a writer wants to enter the database but has to wait, then no reader may enter. Of course, the writer still has to wait for the current readers in the database to finish their transactions.
Requirements:
• Your program should accept the number of readers and number of writers as a parameter in the command line. • Your program name should be RW.java. • Hence the command to run the system will be
>java RW <# of readers> <# of writers>
• In addition to reading and writing, threads should sleep a random amount of time (0 to 1000ms) to simulate a real situation. • Your program should print out the count of writers waiting, readers waiting and also reflect the concurrent behavior of Readers. For this purpose, Readers should print out the reader count value (i.e. number of readers currently reading the database). To make this behavior more clear and easy to observe, you might want to make your Reader threads sleep after incrementing the reader count but before decrementing it.
• wait(): blocks the invoking thread;
• notify(): reactivates one thread blocked in a wait() ;
• notifyAll(): reactivates all threads blocked in a wait() .
[See ReaderWriter2.java]
import java.io.*;
import java.util.*;
public class ReaderWriter2
{
public static void main(String args[])throws IOException
{
System.out.println(" Number of Readers = " + args[0]+ ". ");
System.out.println("nNumber of Writers = " + args[1]+ ". ");
int number_of_readers = Integer.parseInt(args[0]);
int number_of_writers = Integer.parseInt(args[1]);
Database r = new Database();
//array of reader threads
Reader[] readers = new Reader[number_of_readers];
//array of writer threads
Writer[] writers = new Writer[number_of_writers];
System.out.println("Starting... ");
//create all reader threads and make them run
for(int i = 0; i < number_of_readers; i++){
String s = "Reader" + i;
readers[i] = new Reader(r,s);
readers[i].start();
}
//create all writer threads and make them run
for(int i = 0; i < number_of_writers; i++){
String s = "Writer" + i;
writers[i] = new Writer(r,s);
writers[i].start();
}
// all threads are running
// all sending messages to the same object
// we block until all complete
for(int i = 0; i < number_of_readers; i++){
try {
readers[i].join();
}
catch (InterruptedException ie) { }
}
for(int i = 0; i < number_of_writers; i++){
try {
writers[i].join();
}
catch (InterruptedException ie) { }
}
System.out.println("All done..");
}
}
class Writer extends Thread
{
private Database r;
String name;
//constructor
public Writer(Database r, String name)
{
this.r = r;
this.name = name;
}
//will produce integers from 0 to 9
public void run()
{
for (int i=0; i<10; i++)
{
r.setBuf(i);
System.out.println(name + " set buffer to "+i);
//sleep for random amount of time
try
{
sleep ((int)(Math.random()*100));
}
catch(InterruptedException e){ }
}//for
}//run
}
class Reader extends Thread
{
private Database r;
String name;
//constructor
public Reader(Database r, String name)
{
this.r = r;
this.name = name;
}
//will produce integers from 0 to 9
public void run()
{
int val = r.getBuf();
System.out.println(name + " retrieved "+val);
while (val != 9)
{
//sleep for random amount of time
try
{
sleep ((int)(Math.random()*100));
}
catch(InterruptedException e){ }
val = r.getBuf();
System.out.println(name + " retrieved "+val);
}//while
}//run
}
class Database
{
private int val=0;
private boolean readable = false; //let the writer go first
public synchronized void setBuf(int val)
{
this.val=val;
while (readable)
{
try
{
wait();
}
catch(InterruptedException e){ }
}//while
readable = true;
notifyAll();
}
public synchronized Integer getBuf()
{
while(!readable)
{
try
{
wait();
}
catch(InterruptedException e){ }
}//while
readable = false;
notifyAll();
return val;
}
}
Explanation / Answer
METHOD 1: import java.util.concurrent.Semaphore; public class ReaderWriterSolution{ public static final int NUM_OF_READERS = 3; public static final int NUM_OF_WRITERS = 2; public static void main(String args[]){ RWLock database = new Database(); Thread[] readerArray = new Thread[NUM_OF_READERS]; Thread[] writerArray = new Thread[NUM_OF_WRITERS]; for (int i = 0; i < NUM_OF_READERS; i++) { readerArray[i] = new Thread(new Reader(i, database)); readerArray[i].start(); } for (int i = 0; i < NUM_OF_WRITERS; i++) { writerArray[i] = new Thread(new Writer(i, database)); writerArray[i].start(); } } } //**************************************************************** /** * An interface for reader-writer locks. * * In the text we do not have readers and writers * pass their number into each method. However we do so * here to aid in output messages. */ interface RWLock{ public abstract void acquireReadLock(int readerNum); public abstract void acquireWriteLock(int writerNum); public abstract void releaseReadLock(int readerNum); public abstract void releaseWriteLock(int writerNum); } //**************************************************************** /** * Database.java * * This class contains the methods the readers and writers will use * to coordinate access to the database. Access is coordinated using semaphores. */ class Database implements RWLock{ private int readerCount; // the number of active readers private Semaphore mutex; // controls access to readerCount private Semaphore db; // controls access to the database public Database() { readerCount = 0; mutex = new Semaphore(1); db = new Semaphore(1); } public void acquireReadLock(int readerNum) { try{ //mutual exclusion for readerCount mutex.acquire(); } catch (InterruptedException e) {} ++readerCount; // if I am the first reader tell all others // that the database is being read if (readerCount == 1){ try{ db.acquire(); } catch (InterruptedException e) {} } System.out.println("Reader " + readerNum + " is reading. Reader count = " + readerCount); //mutual exclusion for readerCount mutex.release(); } public void releaseReadLock(int readerNum) { try{ //mutual exclusion for readerCount mutex.acquire(); } catch (InterruptedException e) {} --readerCount; // if I am the last reader tell all others // that the database is no longer being read if (readerCount == 0){ db.release(); } System.out.println("Reader " + readerNum + " is done reading. Reader count = " + readerCount); //mutual exclusion for readerCount mutex.release(); } public void acquireWriteLock(int writerNum) { try{ db.acquire(); } catch (InterruptedException e) {} System.out.println("Writer " + writerNum + " is writing."); } public void releaseWriteLock(int writerNum) { System.out.println("Writer " + writerNum + " is done writing."); db.release(); } } //*********************************************************** /** * Reader.java * * A reader to the database. * */ class Reader implements Runnable { private RWLock database; private int readerNum; public Reader(int readerNum, RWLock database) { this.readerNum = readerNum; this.database = database; } public void run() { while (true) { SleepUtilities.nap(); System.out.println("reader " + readerNum + " wants to read."); database.acquireReadLock(readerNum); // you have access to read from the database // let's read for awhile ..... SleepUtilities.nap(); database.releaseReadLock(readerNum); } } ; } //************************************************************** /** * Writer.java * * A writer to the database. * */ class Writer implements Runnable { private RWLock database; private int writerNum; public Writer(int w, RWLock d) { writerNum = w; database = d; } public void run() { while (true){ SleepUtilities.nap(); System.out.println("writer " + writerNum + " wants to write."); database.acquireWriteLock(writerNum); // you have access to write to the database // write for awhile ... SleepUtilities.nap(); database.releaseWriteLock(writerNum); } } } //***************************************************************** /** * Utilities for causing a thread to sleep. * Note, we should be handling interrupted exceptions * but choose not to do so for code clarity. * */ class SleepUtilities { /** * Nap between zero and NAP_TIME seconds. */ public static void nap() { nap(NAP_TIME); } /** * Nap between zero and duration seconds. */ public static void nap(int duration) { int sleeptime = (int) (NAP_TIME * Math.random() ); try { Thread.sleep(sleeptime*1000); } catch (InterruptedException e) {} } private static final int NAP_TIME = 5; } METHOD 2: import java.util.Random; class Database { private Random generator = new Random(); private int data = 0; // the "database" int nr = 0; private synchronized void startRead() { nr++; } private synchronized void endRead() { nr--; if (nr==0) notify(); // awaken waiting Writers } public void read() { startRead(); System.out.println("read: " + data); endRead(); } public synchronized void write() { int temp; while (nr>0) try { wait(); } catch (InterruptedException ex) {return;} temp = data; data = 99999; // to simulate an inconsistent temporary state try { Thread.sleep(generator.nextInt(500)); // wait a bit } catch (java.lang.InterruptedException e) {} data = temp+1; // back to a safe state System.out.println("wrote: " + data); notify(); // awaken another waiting Writer } } class Reader extends Thread { int rounds; Database RW; private Random generator = new Random(); public Reader(int rounds, Database RW) { this.rounds = rounds; this.RW = RW; } public void run() { for (int i = 0; i<rounds; i++) { try { Thread.sleep(generator.nextInt(500)); } catch (java.lang.InterruptedException e) {} RW.read(); } } } class Writer extends Thread { int rounds; Database RW; private Random generator = new Random(); public Writer(int rounds, Database RW) { this.rounds = rounds; this.RW = RW; } public void run() { for (int i = 0; i<rounds; i++) { try { Thread.sleep(generator.nextInt(500)); } catch (java.lang.InterruptedException e) {} RW.write(); } } } class ReadWrite { // driver program -- two readers and two writers static Database RW = new Database(); public static void main(String[] arg) { int rounds = Integer.parseInt(arg[0],10); new Reader(rounds, RW).start(); new Reader(rounds, RW).start(); new Writer(rounds, RW).start(); new Writer(rounds, RW).start(); } }
Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.