Java中PrintStream的线程安全性

3

我正在尝试写入文件。我需要能够“追加”到文件而不是覆盖它。此外,我需要它是线程安全和高效的。我当前拥有的代码是:

private void writeToFile(String data) {
    File file = new File("/file.out");
    try {
      if (!file.exists()) {
        //if file doesnt exist, create it
        file.createNewFile();
      }
      PrintStream out = new PrintStream(new FileOutputStream(file, true));
      DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
      Date date = new Date();
      out.println(dateFormat.format(date) + " " + data);

      out.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

一切运作良好。我只是不知道PrintStream是否线程安全。因此,我的问题是:从几个PrintStream实例写入同一个物理文件是否安全?如果安全,它是否使用锁定(降低性能)或排队?你是否知道任何原生Java库具有线程安全并使用排队的功能?如果没有,我没有问题编写自己的库。我只是想看看是否有原生的库。


PrintStream 的方法是 synchronized 同步的。通过写缓冲区实现了排队。 - Marko Topolnik
3
在您的情况下,PrintStream本身的线程安全并不重要,因为您只通过本地实例访问它。您的意思是询问从几个PrintStream实例同时写入同一物理文件是否安全? - assylias
@assylias 是的。感谢您的纠正。我会编辑我的问题以反映这一点。 - Nick Humrich
https://dev59.com/0HVC5IYBdhLWcg3w-mVO - assylias
不要使用多个PrintStream实例,只需看看日志记录器的工作原理 - 一个线程(消费者)不断地写入文件,其他线程使用阻塞队列给他分配任务(生产者)。 - Maciej Dobrowolski
@MaciejDobrowolski 我想阻塞队列会是我的答案。感谢您的建议。 - Nick Humrich
1个回答

3

PrintStream源码表明它是线程安全的。

如果您想从不同的线程写入相同的文件,为什么不在这些线程之间共享同一个PrintStream实例呢?PrintStream会为您完成同步。

/**
 * Prints a String and then terminate the line.  This method behaves as
 * though it invokes <code>{@link #print(String)}</code> and then
 * <code>{@link #println()}</code>.
 *
 * @param x  The <code>String</code> to be printed.
 */
public void println(String x) {
    synchronized (this) {
        print(x);
        newLine();
    }
}

锁是每个实例独立的 - 这个问题涉及到多个实例。 - assylias
这是我想到的一个想法,但如果我这样做,它会使用锁定还是排队? - Nick Humrich
@anonymous 我有多个实例而不是单个实例并没有特定的原因。然而,除非它使用队列阻塞而不是锁定阻塞,否则拥有单个实例并不能为我带来太多好处。 - Nick Humrich
如果这是意图,您可以为线程实现一个联系点,让这个人只缓冲并批量写入文件。因此,线程不会等待I/O。I/O痛苦由一个单独的人承担,他将写入文件。 - anonymous
@anonymous 这正是我所期望的。在数据被“排队”等待 I/O 的同时,线程可以继续执行它们以前的任务,即使文件当前被锁定。我想我只能实现一个阻塞队列来完成这个功能。 - Nick Humrich
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接