Java文件锁定方式由多个线程以及多个进程组成

时间:2016-06-08 06:43:27

标签: java multithreading synchronization interprocess file-locking

我有超过3个java进程访问同一个文件进行读写。每个进程都有多个线程,可以非常频繁地读写文件(在1秒内以10次左右的速率)。

我使用java.nio.channels.FileLock进行进程间文件锁定。 和commonObj.wait() commonObj.notify()进行同步同步。

我在此实现中遇到的问题是 -

    其中一个进程发生
  1. java.io.IOException: Resource deadlock avoided异常。
  2. 其中一个进程的文件读取器线程获取空文件可能是因为某些其他线程或进程正在写文件。
  3. 我的问题是,

    1. 如果线程在读取或写入完成后立即释放文件锁定,那么为什么会出现问题1?
    2. 如果文件在读取之前被所有进程的每个线程锁定或 写那么为什么会出现2个问题?
    3. 我为所有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;
          }
      }

1 个答案:

答案 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中的类似示例。