8

当 Java 程序调用 System.out.println() 或 Scala 程序调用 println() 时,线程会阻塞吗?

我正在编写一个包含大量子任务的 Scala 程序。每个子任务都在 Future 中执行。建议actors和futures内部的代码不要阻塞,这样后续的任务也不必等待。但我非常想在控制台上打印。

如果是阻塞操作:我可以做些什么来优化性能?

  • 我应该为控制台输出使用专用线程,以便该线程是唯一阻塞的线程吗?
  • 还有其他建议吗?

当然我可以尝试减少输出的数量,或者在一个StringBuilder中收集一些输出,然后批量打印出来,这样可以减少输出操作的次数。

4

2 回答 2

14

当 Java 程序调用 System.out.println() 或 Scala 程序调用 println() 时,线程会阻塞吗?

是和不是。 System.outPrintStream一个同步类。因此,写入大量数据的多个线程System.out肯定会相互阻塞。然而,一旦线程获得锁,IO 是否会阻塞线程取决于架构。如果您写入大量 IO,超出了底层硬件的容量,则写入阻塞。此外,进行大量小写入(而不是缓冲的)也会减慢线程。

我应该为控制台输出使用专用线程,以便该线程是唯一阻塞的线程吗?

好主意,是的。然后这个线程可以通过单个BufferedWriter或某种 log4j 或其他日志包写入,与System.out. 您将需要使用类似 a 的东西将BlockingQueue同步的消息排队,但 IO 永远不会阻塞此队列,除非您生成消息的速度快于 IO 通道可以持久保存它们的速度。

当然我可以尝试减少输出的数量,或者在一个StringBuilder中收集一些输出,然后批量打印出来,这样可以减少输出操作的次数。

我们BufferedWriter会为您解决这个问题。

还有其他建议吗?

  • 如前所述,使用更好的日志记录包或单线程编写器。
  • 将日志写入具有更多 IO 带宽的不同物理磁盘。
  • 切换到内存文件系统或硬件以增加 IO 带宽。固态硬盘++。
  • 通过网络将其发送到另一个盒子以执行实际的持久关闭盒子。
  • 使用 aGzipOutputStream即时压缩它。
于 2013-06-25T17:46:45.217 回答
5

这取决于. 在Windows操作系统上,这是一个阻塞操作,涉及到很多内核内容以将某些内容打印到控制台。在类 UNIX操作系统中,该操作被缓冲,因此不会被认为很慢。

我建议您使用缓冲区方法,并且有一个单独的线程也是一个好主意。或者,如果您的输出不那么重要,您可以将其写入文件,这比写入控制台要快得多。

于 2013-06-25T17:45:32.717 回答