【问题标题】:How to synchronize file access in a Java servlet?如何在 Java servlet 中同步文件访问?
【发布时间】:2014-08-28 11:55:45
【问题描述】:

为了一个简单的目的,我创建了一个小型 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 几乎同时被两个或多个对 servlet 的 http 请求调用。为了避免对同一个文件的多个并行写访问,我需要以某种方式同步它。根据我对 servlet 生命周期过程的理解,每个请求都会产生一个新线程,因此使用 FileLock 可能不会有任何影响:

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

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

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

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

【问题讨论】:

  • 在处理文件时重命名文件?我想使用数据库而不是文件不是您的决定吗?
  • 如果您的应用程序是唯一一个写入文件的应用程序(并且不是集群),则同步可以正常工作。人们通常使用为您处理并发访问的数据库。
  • 您想究竟在此处同步什么?是读-写-写的整个过程吗?或者是个人读写,而处理可以交织在一起(并且您可以从旧读取中写回数据)?
  • @Fildor 正确,目前没有选择使用数据库
  • @JBNizet 所以我只需将我发布的代码包装成synchronized(){} 就可以了?

标签: java file concurrency synchronized filelock


【解决方案1】:

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

【讨论】:

  • 不,锁对象在这里很重要
【解决方案2】:

您可以使用Semaphore,如下:

private static Semaphore semaphore = new Semaphore(1);

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

        // doSomeChangesTo

    } finally {
        semaphore.release();
    }
}

【讨论】:

  • 即使对象被多个子类使用,我也可以使用这个概念吗? @troig
  • 嗨@hanish!不知道我是否明白你们的意思,但我看不出有什么问题。
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 2011-04-05
    • 1970-01-01
    • 2012-12-30
    • 2015-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-10
    • 1970-01-01
    相关资源
    最近更新 更多