• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Threads: Multiple Readers and One writer

 
Greenhorn
Posts: 27
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 27
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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);
}
 
Ranch Hand
Posts: 1646
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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.

  •  
    Consider Paul's rocket mass heater.
    reply
      Bookmark Topic Watch Topic
    • New Topic