如何在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。 为了避免对同一文件进行多次并行写访问,我需要以某种方式同步它。 根据我对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(); } } 

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