我有超过3个java进程访问同一个文件进行读写。每个进程都有多个线程,可以非常频繁地读写文件(在1秒内以10次左右的速率)。
我使用java.nio.channels.FileLock
进行进程间文件锁定。
和commonObj.wait()
commonObj.notify()
进行同步同步。
我在此实现中遇到的问题是 -
java.io.IOException: Resource deadlock avoided
异常。我的问题是,
我为所有java进程编写了常见的reader writer类。附上相同的。
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;
}
}
答案 0 :(得分:0)
我认为你在Linux上运行这个程序。 java将使用(主要是)POSIX lock http://www.man7.org/linux/man-pages/man2/fcntl.2.html
请参阅手册中提到的有关EDEADLK的部分。 Linux操作系统很可能无法识别在同一个JVM中运行的2个不同的线程。 请参阅https://gist.github.com/harrah/4714661中的类似示例。