如何在Java servlet中同步文件访问?

时间:2014-08-28 11:55:45

标签: java file concurrency synchronized filelock

我为一个简单的目的创建了一个小型Java servlet:一旦调用它,它将执行以下步骤:

  1. 从本地文件系统
  2. 读取文件foo.json
  3. 处理文件中的数据并对其进行一些更改
  4. 将更改写回文件
  5. 简化版代码:

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        FileInputStream inputStream = new FileInputStream("foo.json");
        String filecontent = IOUtils.toString(inputStream);
        inputStream.close();
    
        JSONObject json = new JSONObject(filecontent);
    
        doSomeChangesTo(json);
    
        FileWriter writer = new FileWriter("foo.json");
        writer.write(json.toJSONString());
        writer.flush();
        writer.close();
    }
    

    现在我面临的问题是,可能会发生几乎同时通过两个或多个对servlet的http请求调用servlet。为了避免对同一文件进行多次并行写访问,我需要以某种方式同步它。根据我对servlet生命周期过程的理解,每个请求都会生成一个新线程,因此使用FileLock可能没有任何影响:

      

    代表整个Java虚拟机保存文件锁。他们   不适合控制多个线程对文件的访问   在同一个虚拟机中。

    (来自http://docs.oracle.com/javase/7/docs/api/java/nio/channels/FileLock.html

    我想使用synchronized(){}关键字也不起作用,因为我想同步文件系统访问而不是访问变量/对象。

    那么,当该servlet上发生多个并行请求时,如何在我的servlet中同步文件系统访问?

3 个答案:

答案 0 :(得分:8)

  

我想使用synchronized(){}关键字也不起作用,因为我想同步文件系统访问而不是访问变量/对象。

使用synchronized可以正常工作。您假设如果要控制从多个线程对对象 X 的访问,则必须在该对象上使用synchronized。你没有。您可以在任何对象上使用synchronized,前提是所有访问都使用相同的对象。

事实上,使用单独的private锁定对象进行同步通常更好,因为类之外的代码不可能在锁上进行同步。

所以,你可能会有这样的事情,每个共享文件都有一个实例:

 public class SharedFile
 {
      private final File path;
      private final Object lock = new Object();

      public SharedFile(File path) {
         this.path = path;
      }

      public void process(.....) throws IOException {
         synchronized(lock) {
            try(InputStream = new FileInputStream(path)) {
               ....
            }
         }
      }
 }

答案 1 :(得分:3)

您可以使用Semaphore,如下所示:

private static Semaphore semaphore = new Semaphore(1);

public void doSomeChangesTo(JSONObject json) {
    try {
        semaphore.acquire();

        // doSomeChangesTo

    } finally {
        semaphore.release();
    }
}

答案 2 :(得分:0)

您应该使用信号量来保护对资源的访问。 (您的文件。)请参阅http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html