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