What does flush() do on an output stream, and when do you need to call it explicitly?
answer
- flush() = push JVM buffer -> underlying stream/OS now
- close() flushes automatically; explicit flush mainly for still-open sockets
- flush != durable: OS page cache; need FileChannel.force / FD.sync for disk
- Unflushed write on a socket can deadlock the protocol
- autoFlush on PrintWriter/PrintStream flushes on newline/println
basics
~20 sflush() pushes data that is sitting in an in-memory buffer out to the underlying destination (file, socket, OS). You need it when you want buffered bytes to appear before you close the stream, such as on a long-lived socket.
solid answer
~40 sBuffered output streams hold bytes in memory and write them to the OS in bigger batches for performance. flush() forces that buffer out to the underlying stream/OS immediately. You rarely need it for a file you're about to close, because close() flushes automatically. You DO need explicit flush() when the stream stays open and the other side is waiting for the data: a network socket where the peer expects a complete request before replying, an interactive protocol, or a log that must be visible promptly. Note that flush() only guarantees the data left the JVM buffer toward the OS; it does NOT guarantee the OS wrote it to physical disk. For durability you need the OS-level sync: FileChannel.force(true) or FileDescriptor.sync(). PrintWriter/PrintStream can be constructed with autoFlush, which flushes on newline or println.
code
java · 13 lines// Socket request-response: MUST flush so the peer sees the request
try (Socket s = new Socket(host, port)) {
BufferedWriter out = new BufferedWriter(
new OutputStreamWriter(s.getOutputStream(), StandardCharsets.UTF_8));
out.write("GET /status\n");
out.flush(); // without this, bytes sit in the buffer -> deadlock
// ... now read the response from s.getInputStream()
}
// File case: no explicit flush needed; close() flushes for us
try (BufferedWriter w = Files.newBufferedWriter(path, StandardCharsets.UTF_8)) {
w.write("line\n");
} // close() flushes the buffer, then closesgo deeper
Knows flush() pushes out buffered data and that close() flushes automatically.
Explains buffering's purpose, when explicit flush is required (open sockets/interactive output), and autoFlush on PrintWriter/PrintStream.
Distinguishes flush (JVM->OS) from durability/sync (OS->device), explains the socket-deadlock scenario, and the performance cost of over-flushing.
Reasons about durability guarantees end-to-end (fsync, write barriers), batching/latency trade-offs, and where flush/sync policy belongs in a system's reliability design.
## Buffering, and why it exists Writing one byte at a time to disk or a network is slow: each call may cross into the OS (a **system call**), which is expensive. To speed this up, classes like `BufferedOutputStream` and `BufferedWriter` keep an in-memory byte/char array (the **buffer**). Your `write()` calls just copy into that array; only when the array fills (or you flush/close) does the class make one big system call to the underlying stream. Fewer, larger writes = much faster I/O. ## What flush() actually does `flush()` says: 'take whatever is currently in your in-memory buffer and write it now to the thing beneath you.' For a chain like `BufferedWriter -> FileWriter -> OS`, flushing the `BufferedWriter` pushes its buffer down to the `FileWriter`, which pushes to the OS. The contract is on `Flushable`, implemented by output streams and writers. **Crucial limit:** flush() only moves data from the **JVM's** buffer toward the **OS**. The OS itself has its own write-back cache (the page cache). After flush(), the bytes may still be sitting in OS memory, not yet on the physical disk platter/SSD. If the machine loses power right then, the data can be lost. To force the OS to persist to the device you need a separate, much heavier operation: `FileChannel.force(true)` or `FileOutputStream.getFD().sync()`. This distinction (flush = JVM->OS, sync = OS->device) is a common senior-level gotcha. ## When you must flush explicitly 1. **Long-lived sockets / request-response protocols.** You write a request to a `Socket`'s output stream and then read the response. If your write is buffered and unflushed, the bytes never leave; the peer waits forever for a request that's stuck in your buffer, and you wait for a reply — a deadlock. Flush after writing the complete message. 2. **Interactive / streaming output** where the consumer reads incrementally (a chat, a progress log, server-sent events). 3. **Before reading on a bidirectional pipe.** ## When you usually DON'T need it If you're going to `close()` the stream right after writing — the common file-writing case — you don't need an explicit flush(), because **close() flushes first**. Calling flush() then close() is harmless but redundant. (Inside try-with-resources, close() is automatic, so flush is rarely written there.) ## autoFlush `PrintWriter` and `PrintStream` (e.g. `System.out`) accept an `autoFlush` flag. When true, they flush automatically — `PrintStream` on every newline byte and on `write(byte[])`; `PrintWriter` on `println`/`printf`/`format`. That's why `System.out.println` appears immediately. With autoFlush off and buffering on, output can appear to 'disappear' until close. ## flush() vs close() - `flush()` empties the buffer but keeps the stream open and usable. - `close()` flushes once, then releases the resource; further writes throw. ## Edge: unbuffered streams A raw `FileOutputStream` (no buffer wrapper) writes straight through, so flush() on it is essentially a no-op — there's nothing buffered in the JVM. flush() only matters where buffering exists.
- Does flush() guarantee the data is safely on disk?No. flush() only moves data from the JVM buffer to the OS. The OS may still hold it in its page cache. For durability you must call FileChannel.force(true) or FileOutputStream.getFD().sync(), which force the OS to write to the physical device.
- Why does System.out.println appear immediately even though it's a PrintStream?System.out is created with autoFlush enabled, so PrintStream flushes on each newline (and on byte-array writes), making output appear right away.
Buffering is like writing a shopping list before going to the store. flush() is the trip to the store (you act on what you've written). But the goods sitting in your car (OS cache) aren't in the kitchen yet — sync() is carrying them inside and putting them away (durably on disk).
saying these in an interview costs you the question
- Believing flush() makes data durable on disk (it doesn't; that's sync/force)
- Calling flush() before every write 'to be safe', destroying buffering performance
- Forgetting to flush a buffered socket stream and then blaming a 'hang'
- Thinking flush() on an unbuffered FileOutputStream does something meaningful