【问题标题】:Java concurrent writes from multiple threads to a single text file?Java从多个线程并发写入单个文本文件?
【发布时间】:2015-08-17 04:44:08
【问题描述】:

我有一个使用 JDBC 执行工作的多线程 Java 7 程序(一个 jar 文件)(它使用一个固定的线程池)。

程序运行良好,它会在从多个并发线程进入命令 shell 控制台窗口 (System.out.printf()) 时记录内容。

除了控制台输出之外,我还需要为该程序添加从多个线程写入单个纯 ASCII 文本日志文件的功能。

输出量小,文件会比较小,因为是日志文件,不是数据文件。

您能否建议一个好的且相对简单的设计/方法来使用 Java 7 功能(我还没有 Java 8)来完成这项工作?

任何代码示例也将不胜感激。

非常感谢

编辑:

我忘了补充:在 Java 7 中使用 Files.newOutputStream() 静态工厂方法被声明为线程安全的 - 根据官方 Java 文档。这是从多个线程写入单个共享文本日志文件的最简单选项吗?

【问题讨论】:

  • 为什么不使用像 slf4j slf4j.org/manual.html 这样的标准日志 API?
  • 否则,如果您只想坚持使用 jdk api,请参阅:stackoverflow.com/questions/5950557/…
  • 忘记补充:在 Java 7 中使用 Files.newOutputStream() 静态工厂方法被声明为线程安全的 - 根据官方 Java 文档。这是从多个线程写入单个共享文本日志文件的最佳选择吗?
  • 写代码的请求?

标签: java multithreading file java-7


【解决方案1】:

如果你想记录输出,为什么不使用日志库,例如log4j2?这将允许您根据您的特定需求定制您的日志,并且可以在不同步 stdout 上的线程的情况下进行日志记录(您知道运行 System.out.print 涉及锁定 System.out?)

编辑:对于后者,如果您记录的内容是线程安全的,并且您可以将LMAX' disruptor.jar 添加到您的构建中,您可以配置具有日志记录线程的异步记录器(只需添加“async”)处理整个消息的格式和写入(并保持日志消息的顺序),同时让您的线程顺利运行。

【讨论】:

  • Java 已将记录器包含在 JDK (java.util.Logger) 中。在文档中,他们提到 Logger 上的所有方法都是多线程安全的。 docs.oracle.com/javase/7/docs/api/java/util/logging/Logger.html
  • 是的,但是与 log4j2 相比,默认的记录器实现速度很慢。当然,它可能仍然比 System.out.println 快,但为什么不使用当前最好的选项呢?顺便说一句,您记录的 things 必须是线程安全的,因为例如如果您记录 Map 并且同时对其进行了修改,则您的记录器可能会抛出 ConcurrentModificationException。在这种情况下,在 log. 调用中复制或使用 .toString()。
【解决方案2】:

鉴于你说输出量很低,最简单的选择可能是只编写一个线程安全的编写器,它使用同步来确保只有一个线程实际上可以写入一次到文件。

如果您不希望线程相互阻塞,您可以使用BlockingQueue 使用一个专用于写入的线程 - 线程将写入作业(以它们需要的任何形式 - 可能只是作为字符串)添加到队列,单线程从队列中取出值并将它们写入文件。

无论哪种方式,都值得将专门用于此目的的类背后的细节抽象出来(出于可测试性和灵活性的原因,最好实现一个接口)。这样您就可以在以后更改实际的底层实现 - 例如,从同步方法开始,然后在需要时移至生产者/消费者队列。

【讨论】:

  • 感谢 Jon,我实现了队列和一个单独的线程来写入文件,似乎运行良好。
【解决方案3】:

保留一个通用的 PrintStream 引用(而不是 System.out)并将其设置为 System.out 或将其引导至 FileOutputStream,具体取决于您的需要。

您的代码不会有太大变化(几乎没有),PrintStream 也已经同步。

【讨论】:

  • 另一方面,PrintStream 吞下异常 - 我在 文档 中看不到任何说明操作是同步的...
  • 嗯,我正在考虑建议你的回答,但选择了极低工作量的版本。
  • @Ouney 是的,我们知道 PrintStream 的热点版本是线程安全的。然而,它没有在任何文档中断言(我们不知道 OP 是否正在使用 Hotspot)。
猜你喜欢
  • 1970-01-01
  • 2012-04-19
  • 1970-01-01
  • 2015-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多