Java文件多线程多进程加锁方式

cod*_*try 5 java multithreading synchronization file-locking interprocess

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

我用于java.nio.channels.FileLock进程间文件锁定。以及commonObj.wait() commonObj.notify()线程间同步。

我在此实施中面临的问题是 -

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

我的问题是,

  1. 如果线程在读取或写入完成后立即释放文件锁,那么为什么会出现问题 1?
  2. 如果文件在读取或写入之前被所有进程的每个线程锁定,那么为什么会出现 2 个问题?

我已经为所有 java 进程编写了通用的读写器类。附上一样的。

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

pre*_*kal 1

我认为你正在Linux上运行这个程序。java将使用(主要)POSIX锁http://www.man7.org/linux/man-pages/man2/fcntl.2.html

请参阅手册中提到 EDEADLK 的部分。Linux 操作系统很可能无法识别同一 JVM 内运行的 2 个不同线程。请参阅https://gist.github.com/harrah/4714661中的类似示例。