简体   繁体   English

Java文件通过多个线程以及多个进程锁定的方式

[英]Java file locking way by multiple threads as well as multiple processes

I have more then 3 java processes accessing same file for read and write. 我有3个以上的Java进程访问同一文件进行读写。 Each process has multiple threads that read and write file very frequently (at the rate of 10 times or so in 1 second). 每个进程都有多个线程,这些线程非常频繁地读写文件(在1秒钟内大约10倍的速率)。

I am using java.nio.channels.FileLock for interprocess file locking. 我正在使用java.nio.channels.FileLock进行进程间文件锁定。 And commonObj.wait() commonObj.notify() for interthread synchronization. commonObj.wait() commonObj.notify()用于线程间同步。

The issue I am facing in this implementation is - 我在此实施过程中面临的问题是-

  1. java.io.IOException: Resource deadlock avoided exception occurs in one of the process. java.io.IOException: Resource deadlock avoided异常发生的过程之一。
  2. 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, 我的问题是

  1. if thread releases file lock as soon as read or write is done then why issue 1 occurs ? 如果线程在读取或写入完成后立即释放文件锁定,那么为什么会发生问题1?
  2. if file is locked by each thread of all the processes before read or write then why does 2 issue occurs ? 如果文件在读取或写入之前被所有进程的每个线程锁定,那么为什么会发生2个问题?

I have written common reader writer classes for all java processes. 我已经为所有Java进程编写了通用的Reader writer类。 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; } } 

I think you are running this program on linux. 我认为您正在Linux上运行此程序。 The java will be using (mostly) POSIX lock http://www.man7.org/linux/man-pages/man2/fcntl.2.html Java将(主要)使用POSIX锁http://www.man7.org/linux/man-pages/man2/fcntl.2.html

See the part where the manual mentions about EDEADLK. 请参阅手册中提及EDEADLK的部分。 The linux OS is most probably unable to identify that 2 different threads are running inside the same JVM. linux操作系统很可能无法识别在同一个JVM中正在运行2个不同的线程。 see a similar example in https://gist.github.com/harrah/4714661 here. 请参阅https://gist.github.com/harrah/4714661此处的类似示例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM