I have more then 3 java processes accessing same file for read and write. Each process has multiple threads that read and write file very frequently (at the rate of 10 times or so in 1 second).
I am using java.nio.channels.FileLock
for interprocess file locking.
And commonObj.wait()
commonObj.notify()
for interthread synchronization.
The issue I am facing in this implementation is -
java.io.IOException: Resource deadlock avoided
exception occurs in one of the process.- One of the process's file reader thread gets empty file may be because some other thread or process is writing file.
My question is,
- if thread releases file lock as soon as read or write is done then why issue 1 occurs ?
- if file is locked by each thread of all the processes before read or write then why does 2 issue occurs ?
I have written common reader writer classes for all java processes. Attaching the same.
package json_file_handler;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.log4j.Logger;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
public class JsonReader {
final static Logger logger = Logger.getLogger(JsonReader.class);
static final ReentrantLock relock = new ReentrantLock();
/**
* Read given file in JSONObject
* @param fileName String
* @return JSONObject
*/
@SuppressWarnings("resource")
public static JSONObject readJsonFile(String fileName) {
JSONObject createdJsonObj = null;
JSONParser jsonParser = new JSONParser();
FileChannel channel = null;
FileLock lock = null;
FileReader fileReader = null;
boolean islocked = false;
try
{
while(!islocked)
{
try
{
File file = new File(fileName);
channel = new RandomAccessFile(file, "rw").getChannel();
lock = channel.lock();
if(lock != null)
{
islocked = true;
fileReader = new FileReader(fileName);
createdJsonObj = (JSONObject) jsonParser.parse(fileReader);
}
}
catch(OverlappingFileLockException e)
{
logger.error("FILE LOCK OVERLAP EXP OCCURED IN READING FILE " + fileName
+". ATTEMPTING TO READ FILE AGAIN.");
//Thread.sleep(1);
//release the lock
if(lock != null)
{
lock.release();
}
// close the channel
if(channel != null)
{
channel.close();
}
synchronized (relock) {
relock.wait();
}
}
} //while
}
catch (FileNotFoundException e)
{
e.printStackTrace();
logger.error("FILE NOT FOUND ERROR IN READING JSON FOR FILE NAMED "+fileName+".",e);
}
catch (IOException e)
{
e.printStackTrace();
logger.error("IO ERROR IN READING JSON FOR FILE NAMED "+fileName+".",e);
}
catch (ParseException e)
{
e.printStackTrace();
logger.error("PARSING ERROR IN JSON FOR FILE NAMED "+fileName+".",e);
}
catch (Exception e)
{
e.printStackTrace();
logger.error("ERROR IN JSON FOR FILE NAMED "+fileName+".",e);
}
finally {
try {
if(fileReader != null)
{
fileReader.close();
}
// release the lock
if(lock != null)
lock.release();
// close the channel
if(channel != null)
{
channel.close();
}
}
catch (IOException e) {
e.printStackTrace();
logger.error("IO ERROR IN CLOSING FILE "+fileName+".",e);
}
catch (Exception e) {
e.printStackTrace();
logger.error("ERROR IN CLOSING FILE "+fileName+".",e);
}
finally {
synchronized (relock) {
relock.notify();
}
}
}
return createdJsonObj;
}
}
package json_file_handler;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException;
import org.apache.log4j.Logger;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class JsonWriter {
final static Logger logger = Logger.getLogger(JsonWriter.class);
/**
* Write given JSONObject into given file name
* @param fileName String
* @param ObjToWrite JSONObejct
* @return boolean true on success else false
*/
@SuppressWarnings("resource")
public static boolean writeJsonFile(String fileName, JSONObject ObjToWrite) {
boolean writeFlag = false;
FileChannel channel = null;
FileLock lock = null;
FileWriter fileWriter = null;
boolean islocked = false;
try
{
while(!islocked)
{
try
{
File file = new File(fileName);
channel = new RandomAccessFile(file, "rw").getChannel();
lock = channel.lock();
if(lock != null)
{
islocked = true;
fileWriter = new FileWriter(fileName);
Gson gson2 = new GsonBuilder().setPrettyPrinting().create();
String json2 = gson2.toJson(ObjToWrite);
fileWriter.write(json2);
writeFlag = true;
}
}
catch(OverlappingFileLockException e)
{
logger.error("FILE LOCK OVERLAP EXP OCCURED IN WRITING FILE " + fileName
+". ATTEMPTING TO WRITE FILE AGAIN.");
//release the lock
if(lock != null)
{
lock.release();
}
// close the channel
if(channel != null)
{
channel.close();
}
synchronized (JsonReader.relock) {
JsonReader.relock.wait();
}
}
}
}
catch (FileNotFoundException e)
{
e.printStackTrace();
logger.error("FILE NOT FOUND ERROR IN WRITING JSON FOR FILE NAMED "+fileName+".",e);
}
catch (IOException e)
{
e.printStackTrace();
logger.error("IO ERROR IN WRITING JSON FOR FILE NAMED "+fileName+".",e);
}
catch (Exception e)
{
e.printStackTrace();
logger.error("ERROR IN JSON FOR FILE NAMED "+fileName+".",e);
}
finally {
try {
if(fileWriter != null)
{
fileWriter.flush();
fileWriter.close();
}
// release the lock
if(lock != null)
lock.release();
// close the channel
if(channel != null)
{
channel.close();
}
}
catch (IOException e) {
e.printStackTrace();
logger.error("IO ERROR IN CLOSING FILE "+fileName+".",e);
}
catch (Exception e) {
e.printStackTrace();
logger.error("ERROR IN CLOSING FILE "+fileName+".",e);
}
finally {
synchronized (JsonReader.relock) {
JsonReader.relock.notify();
}
}
}
return writeFlag;
}
}