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



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

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

代码的简化版本:

@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生命周期过程的理解,每个请求都会产生一个新的线程,因此使用FileLock可能不会产生任何影响:

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

(发件人http://docs.oracle.com/javase/7/docs/api/java/nio/channels/FileLock.html)

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

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

我想使用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)) {
               ....
            }
         }
      }
 }

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

private static Semaphore semaphore = new Semaphore(1);
public void doSomeChangesTo(JSONObject json) {
    try {
        semaphore.acquire();
        // doSomeChangesTo
    } finally {
        semaphore.release();
    }
}

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

相关内容

  • 没有找到相关文章

最新更新