8

When a Java program calls System.out.println() or a Scala program calls println() does the thread block?

I'm writing a Scala program with a huge amount of subtasks. Each subtask is executed inside a Future. It is recommended that code inside actors and futures does not block, so that subsequent tasks don't have to wait, too. But I want to print very much on the console.

And if it is a blocking operation: What can I do to optimize performance?

  • Should I use a dedicated thread for console output, so that thread is the only one that blocks?
  • Any other advices?

Of course I could try to reduce the amount of output or collect some output in a StringBuilder and print it together in a batch, which reduces the number of output operations.

user573215
  • 4,679
  • 5
  • 22
  • 25

2 Answers2

14

When a Java program calls System.out.println() or a Scala program calls println() does the thread block?

Yes and no. System.out is a PrintStream which is a synchronized class. So multiple threads writing large amounts to System.out will block each other for sure. Once a thread gets the lock however, whether or not the IO will block the thread is architecture dependent. If you write a large amount of IO that overwhelms the capacity of the underlying hardware then the write will block. Also, making a lot of small writes (as opposed to buffered), will slow the thread as well.

Should I use a dedicated thread for console output, so that thread is the only one that blocks?

Excellent idea, yes. Then this thread could write through a single BufferedWriter or some sort of log4j or other logging package which would be a lot more performant compared to System.out. You will need to use something like a BlockingQueue to queue up the messages which is synchronous but the IO will never block this queue unless your are producing messages faster than the IO channel can persist them.

Of course I could try to reduce the amount of output or collect some output in a StringBuilder and print it together in a batch, which reduces the number of output operations.

The BufferedWriter will take care of this for you.

Any other advices?

  • As mentioned, use a better logging package or a single-threaded writer.
  • Write logs to a different physical disk that has more IO bandwidth.
  • Switch to a memory file-system or hardware to increase your IO bandwidth. SSD++.
  • Send it via the network to another box to do the actual persisting off box.
  • Use a GzipOutputStream to compress it on the fly.
Gray
  • 115,027
  • 24
  • 293
  • 354
  • *Write logs to a different file system.* You mean different physical drive? Or if you mean that one file system is optimized better for such tasks than another (e.g. ext* versus btrfs), could you reveal the names? – om-nom-nom Jun 25 '13 at 17:53
  • No, I really mean IO chain, not different FS type @om-nom-nom. Great user name btw. :-) – Gray Jun 25 '13 at 18:01
  • I've never heard of System.out being "nonblocking". It's not implemented on top of java.nio, is it? If you run with stdout redirected to a file on a slow device, I'm quite sure any calls to System.out.println() will block and not return until the write has completed. Also, I don't think this has anything to do with a printwriter being a synchronized class. You can easily create a java method doing blocking IO without tagging the class or the method "synchronized". At the lowest level, there's a C or kernel call to write() that won't return until complete, blocking the thread until it returns. – faffaffaff Jun 25 '13 at 18:35
  • 1
    It depends on the architecture @faffaffaff. All IO operations are to some extent blocking. What I was trying to explain is that until you fill the IO stream of the device you are writing to (under Unix at least), the write will not block the thread. It will just get copied into a kernel buffer. I've tweaked my answer. – Gray Jun 25 '13 at 18:38
  • OK, but usually "nonblocking IO" has a very specific meaning (and is implemented as a specific mode/option), which is that either the call goes through immediately or it returns with a "write failed, would have blocked", so it's a bit odd to use the expression "to some extent blocking". Either the call always has a risk of blocking, or it is guaranteed to never block (and possibly fail because it won't wait), I think? – faffaffaff Jun 25 '13 at 18:42
  • 1
    This is true from a software perspective but the actual details about whether or not a thread is going to stop and wait for the IO to complete is more complicated @faffaffaff. The OP is asking about performance of multiple threads logging. This is more about the realities of how the OS handles the write operations then the definition of "blocking". – Gray Jun 25 '13 at 18:44
5

It depends. On Windows OS it's a blocking operation and involves a lot of kernel stuff to print something to the console. In UNIX-like OS the operation is buffered so it's not perceived as slow.

I would suggest you go with your buffer approach, and having a separate thread is also a good idea. Or if your output is not as important, you could write it to a file, which is much faster than writing to console.

darijan
  • 9,725
  • 25
  • 38
  • Also remember that System.out does not necessarily print to the console (it might have been redirected to a file with "command > out.txt") – faffaffaff Jun 25 '13 at 18:43