NIO & NIO.2
NIO and NIO.2: the buffer state model, channels, selectors for non-blocking multiplexing, the Path and Files API, and advanced facilities like memory mapping and async channels. Selectors are the part interviewers care about most, because they explain how scalable servers work.
part ofJavaoverview, primer and where to startread it →on this pageshowhide
explore
- Buffer Model: capacity/limit/position/mark5 questions
- Buffer Operations: flip/clear/rewind/compact5 questions
- Buffer Allocation: heap vs direct5 questions
- Channels & FileChannel5 questions
- Non-blocking I/O & Selectors5 questions
- Memory-Mapped Files & File Locking5 questions
- Asynchronous Channels5 questions
- Path & Files API6 questions
- WatchService5 questions
questions
page 2 of 2What do slice(), duplicate(), and asReadOnlyBuffer() create, and how do their markers and backing storage relate to the original buffer?
basics
~20 sAll three make a new buffer that shares the same underlying data as the original (a window onto it) but has its own independent position, limit, and mark. duplicate() mirrors the whole buffer, slice() exposes only the part from position to limit, and asReadOnlyBuffer() makes a view you can read but not write.
Design a robust read loop that copies all bytes from one channel to another using a single ByteBuffer, and explain why each buffer operation is necessary and how partial reads/writes are handled.
basics
~20 sLoop: clear() the buffer, read() from the source into it, if read returns -1 stop, flip() it, then write() to the destination in a loop until no bytes remain. Because a single write() may not drain the whole buffer, you loop on hasRemaining(); flip and clear switch the buffer between filling and draining each iteration.
Explain scatter/gather I/O with channels (read into / write from an array of buffers). What problem does it solve?
basics
~20 sScatter/gather lets a channel read into several buffers in one call (scatter) or write from several buffers in one call (gather). It's useful when a message has fixed parts, like a header and a body — you can read straight into separate buffers, or build a message from separate header and body buffers and write it all at once.
What are FileChannel.transferTo / transferFrom, and why are they called zero-copy? When do they give a real performance win?
basics
~20 stransferTo and transferFrom move bytes directly from one channel to another without you allocating a ByteBuffer and looping read/write yourself. They are called zero-copy because the operating system can move the data inside the kernel without copying it into your Java program's memory, which makes things like serving a file over a socket much faster.
What does MappedByteBuffer.force() do, and why is it important for durability of memory-mapped writes?
basics
~20 sWhen you write through a memory-mapped file, the changes sit in memory and the OS decides when to save them to disk. force() tells the OS to flush those changes to disk now, so they aren't lost if the program or machine crashes.
What are the main pitfalls of memory-mapped files in Java — resource cleanup, the 2 GB limit, and crash safety — and how do you address them?
basics
~20 sMapped files can't be reliably unmapped before the buffer is garbage-collected, so files may stay locked (notably on Windows). One mapping can't exceed about 2 GB. And writes aren't safe on disk until you call force(). Plan for all three.
How does Files.lines() differ from Files.readAllLines(), and what must you be careful about when using it?
basics
~20 sFiles.readAllLines reads the whole file into a List in memory at once. Files.lines returns a lazy Stream that reads line-by-line, so it handles huge files, but you must close the stream (use try-with-resources) because it holds an open file handle.
Compare Files.walk() and Files.walkFileTree() for directory traversal. When would you choose each, and what are the pitfalls?
basics
~20 sFiles.walk returns a lazy Stream of all paths under a directory, great for simple filtering — but you must close it. Files.walkFileTree uses a visitor callback giving fine control over each file, directory entry/exit, and errors, which is better for complex traversals like recursive delete.
What are the common pitfalls when writing a Selector-based server, and how do you avoid them?
basics
~20 sMain pitfalls: forgetting to remove handled keys from selectedKeys() (causes reprocessing), leaving OP_WRITE always on (busy spin), ignoring partial reads/writes, blocking inside the loop, and not handling -1 from read() (peer closed). Fix each by following the correct NIO idioms.
Explain the Reactor pattern and how Java NIO Selectors implement it. Why do servers like Netty use it?
basics
~20 sThe Reactor pattern uses one (or a few) event-loop threads that wait for I/O readiness and dispatch each ready event to a handler. Java's Selector is exactly this: select() detects readiness, and you route OP_READ/OP_WRITE/OP_ACCEPT to the right code. It lets a server handle many connections with few threads.
What is the OVERFLOW event in WatchService, when does it occur, and how should you handle it?
basics
~20 sOVERFLOW means the watch service dropped some change events because they arrived faster than your program consumed them. When you see it, you can't trust your event list is complete, so you should re-scan the directory to find out the real current state.
WatchService only watches a single directory level. How do you watch an entire directory tree, and what edge cases must you handle?
basics
~20 sWatchService doesn't watch subfolders automatically. To watch a whole tree, you walk the directory tree once and register every directory, keep a map from each WatchKey to its directory, and whenever a new subdirectory is created (an ENTRY_CREATE you observe) you register that one too.
Sketch how you would build a scalable TCP echo server with AsynchronousServerSocketChannel and CompletionHandler. What are the key patterns and pitfalls?
basics
~20 sOpen an AsynchronousServerSocketChannel, bind a port, and call accept with a handler. When a client connects, the handler gets the new connection, immediately calls accept again for the next client, and starts reading. Each read's handler writes the data back, then reads again.
What does asReadOnlyBuffer() do, and when would you use it?
basics
~20 sasReadOnlyBuffer() returns a buffer that shares the same data but rejects any write (put throws). You use it to safely hand out a buffer's contents so callers can read but not modify the underlying bytes.
How do you read file attributes (size, timestamps, type, POSIX permissions) with NIO.2, and what is the advantage of the attribute-views model?
basics
~20 sUse the Files helpers like size(), isDirectory(), getLastModifiedTime(), or read a whole bundle with Files.readAttributes(path, BasicFileAttributes.class). For OS-specific data like Unix permissions you request a PosixFileAttributes view. One bulk read is cheaper than many separate calls.
In a high-throughput ingestion service, would you build it around WatchService or a different mechanism? Discuss the trade-offs and how you'd make WatchService production-grade.
basics
~20 sWatchService is great for low-to-moderate change rates because it's efficient and event-driven. For very high throughput or strict reliability, you usually pair it with periodic reconciliation (or replace it), because it can drop events (OVERFLOW), behaves differently per OS, and isn't recursive. The robust design is event-driven for speed plus a safety net that re-scans.
showing 31–46 of 46