my dog learned polymorphism*
The moose likes Threads and Synchronization and the fly likes Threads: Multiple Readers and One writer Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Murach's Java Servlets and JSP this week in the Servlets forum!
JavaRanch » Java Forums » Java » Threads and Synchronization
Bookmark "Threads: Multiple Readers and One writer" Watch "Threads: Multiple Readers and One writer" New topic
Author

Threads: Multiple Readers and One writer

Bill Nelsen
Greenhorn

Joined: Aug 11, 2004
Posts: 27
As a learning exercise, I am trying to implement a scenario where multiple readers are allowed to read a file, but only one writer is allowed to write. As a consequence, no one can read during a write operation. I think that this is the classic MROW problem.

I was looking for the simplest solution. I had hoped that I was on the right track, but it appears that I am missing something. Because I am not seeing any AWOKE messages from the wait() method. So if I am on the wrong track and there is a simpler approach, please let me know.

public class File_locks {
public static String fname = new String("C:/Temp/file.txt");

static public void main(String arg[]) {
Logger logger = Logger.getLogger("file_locks");

// Create a text.file
try {
File file = new File("filename");

// Create file if it does not exist
boolean success = file.createNewFile();
if (success) {
// File did not exist and was created
logger.debug("File did not exist and was created");
} else {
//File already exists
logger.debug("File already exists");
}
} catch (IOException e) {
logger.debug("Can't create new file");
e.printStackTrace();
System.exit(-1);
}

// Ensure that there is enough readers and writers to
// cause conflicts
for (int i = 0; i < 10; i++) {
new ModeThreads("writer" + i).start();
new ModeThreads("reader" + i).start();
}
}
}

class ModeThreads extends Thread {

private static BufferedReader in;
private static BufferedWriter out;
public static String fname = new String("C:/Temp/file.txt");
public static boolean writing = false;
Logger logger = Logger.getLogger("file_locks");

ModeThreads(String name) {
super(name); // Save thread's name
}

public void run() {

while (true) {
if (Thread.currentThread().getName().startsWith("reader")) {
read_withlock(Thread.currentThread().getName());
}
if (Thread.currentThread().getName().startsWith("writer")) {
write_withlock(Thread.currentThread().getName());
}
}
}

// Requirements: Support a multiple number of readers. This precludes simply synchronizing the method
// .
public void read_withlock(String name) {
logger.debug("read_withlock=" + name);

// If a write operation is currently occuring, then wait
// until it is completed
if (writing) {
synchronized (this) {
try {
wait();
logger.debug("AWOKE from wait");
} catch (InterruptedException e) {
logger.debug("interrupted write_withlock");
}
}
}
readFromFile(name);
}

// This works fine, because it supports a single writer
public synchronized void write_withlock(String name) {
logger.debug("read_withlock=" + name);

// It seems that the writing flag needs to be within the critical area, otherwise we could set
// the writing flag, but not get access to the lock
synchronized (this) {
writing = true;
writeToFile(name);
writing = false; // Does this need to come before or after the notify
notify();
}
}

private String readFromFile(String name) {
logger.debug("readFromFile: " + name);
String s = null;
try {
in = new BufferedReader(new FileReader(fname));
s = in.readLine();
logger.debug("readFromFile: " + s);
in.close();
} catch (FileNotFoundException e) {
System.err.println("Could not open " + fname + " for reading");
System.exit(-1);
} catch (Exception e) {
// All other exceptions must close the file
try {
in.close();
} catch (IOException e2) {
System.err.println("in.close() unsuccessful");
}
}
return s;
}

private void writeToFile(String name) {
logger.debug("writeToFile: " + name);

try {
PrintWriter out = new PrintWriter(new BufferedWriter(
new FileWriter(fname)));
out.println(name);
out.close();
} catch (FileNotFoundException e) {
System.err.println("Could not open " + fname);
System.exit(-1);
} catch (Exception e) {
try {
in.close();
} catch (IOException e2) {
System.err.println("in.close() unsuccessful");
System.exit(-1);
}
}
}

}
Bill Nelsen
Greenhorn

Joined: Aug 11, 2004
Posts: 27
Noticed one error. Made a change to the following method:

public void read_withlock(String name) {
logger.debug("read_withlock=" + name);

while (writing == true) {
synchronized (this) {
try {
wait();
logger.debug("AWOKE from wait");
} catch (InterruptedException e) {
logger.debug("interrupted write_withlock");
}
}
}
readFromFile(name);
}
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
Since each Thread synchronizes on itself, once it enters into wait() there's no one to wake it up. You need to have a common object on which to synchronize. Of course, you can't simply do that otherwise you won't allow multiple readers.

Instead, you'll want to use synchronization to control access to a self-contained MROW lock that tracks all the readers and the writer. Synchronization would only wrap the parts that alter the state of the lock -- not around the code that does reading or writing.

Doug Lea's Concurrent Library, which was rolled into JDK 1.5, has many lock (Sync) variants, including locks with reader vs. writer preference.

Here are a couple other random thoughts.
  • You should rarely need "new String" as the string literal is already a String.
  • Unless you're altering how a Thread behaves, it's cleaner to implement Runnable than to extend Thread.
  • Instead of a single class that does reading/writing based on a flag, you might want to create two classes that extend a common parent class.
  • Your ModeThreads instances are sharing a single pair of Reader/Writer, so they're going to interfere with each other. Since the stream classes are synchronized, two readers won't be allowed to read simultaneously.

  •  
    With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
     
    subject: Threads: Multiple Readers and One writer
     
    Similar Threads
    producer-multiple consumers
    StringBuffer to File - Need Example
    Syntax error in INSERT INTO statement
    Accessing files, detemining if they exist...
    Problem with ObjectInputStream