skip to content

What are the MapMode options for FileChannel.map() (READ_ONLY, READ_WRITE, PRIVATE) and how do they differ?

level: middleimportance: should knowfreq 42%

answer

  1. READ_ONLY: writes throw ReadOnlyBufferException
  2. READ_WRITE: writes propagate to the file (force() to flush)
  3. PRIVATE: copy-on-write, changes never saved, never visible to others
  4. READ_WRITE/PRIVATE need channel open for READ+WRITE

basics

~20 s

READ_ONLY lets you only read the file. READ_WRITE lets you read and write, and changes go to the file. PRIVATE lets you write, but your changes stay in memory (copy-on-write) and are never saved back to the file.

solid answer

~40 s

FileChannel.map() takes a MapMode that defines how you may use the mapping. READ_ONLY makes the buffer read-only; attempting to write throws ReadOnlyBufferException, and the channel must be open for reading. READ_WRITE allows both, and modifications are propagated to the underlying file (eventually, or immediately via force()); the channel must be open for read and write. PRIVATE creates a copy-on-write mapping: you can write, but those changes are kept in private pages visible only to your process and are never written back to the file, so other mappers don't see them. PRIVATE still requires read+write access on the channel. Choosing the mode is also a correctness and safety decision: use READ_ONLY whenever you don't need to mutate, both to catch accidental writes and to allow the OS to share pages safely across processes.

go deeper

for a junior

Can name the three modes and state that READ_ONLY only reads, READ_WRITE saves changes, and PRIVATE keeps changes in memory only.

for a middle

Explains copy-on-write semantics of PRIVATE, that READ_WRITE propagates to the file, and the channel-access requirements of each mode.

for a senior

Discusses inter-process visibility, when to prefer READ_ONLY for safety/page sharing, and that PRIVATE changes are unrecoverable/unflushable.

for a principal

Reasons about COW page-fault cost, page-cache sharing across processes, and choosing modes to balance durability, isolation, and memory footprint at scale.

## What MapMode controls When you call `FileChannel.map(MapMode mode, long position, long size)`, the **mode** tells the operating system three things: whether you may write through the mapping, whether your writes reach the file, and whether other processes mapping the same file can see your writes. There are exactly three modes. ### READ_ONLY The returned `MappedByteBuffer` is read-only. Any `put(...)` throws `ReadOnlyBufferException`. The `FileChannel` only needs to be open for reading. This is the safest default when you are just scanning data. Because the pages are never modified by you, the OS can freely share the same physical pages with other processes that map the file read-only. ### READ_WRITE You may read and write. Writes you make to the buffer modify the **shared** mapping, and the OS propagates them to the underlying file — *not necessarily immediately*. The page is marked *dirty* and written back later by the OS's flusher, or right away if you call `force()`. Other processes that have a READ_WRITE or READ_ONLY mapping of the same region will (subject to the OS) observe your changes. The channel must be open for **both read and write**, otherwise `map()` fails (a non-obvious gotcha: opening only for write is not enough). ### PRIVATE (copy-on-write) You may write, but the semantics are *copy-on-write* (COW). Initially the pages are shared with the file. The instant you modify a page, the OS makes a **private copy** of just that page for your process; your write goes to the copy. Consequences: - Your modifications are **never** written back to the file (even `force()` won't persist them). - Other processes never see your modifications. - You still see the file's *unmodified* pages live until you touch them. PRIVATE requires the channel to be open for read+write as well. It's useful when you want a scratch, file-backed view you can mutate freely without disturbing the original — e.g., experimenting on data or presenting a modified view without committing it. ## Quick decision guide - Only reading? **READ_ONLY** — it documents intent, prevents accidental writes, and maximizes page sharing. - Reading and persisting changes? **READ_WRITE** — remember `force()` for durability. - Reading and mutating but *not* persisting? **PRIVATE** — copy-on-write, changes are local and ephemeral. ## Common mistakes Forgetting that READ_WRITE and PRIVATE both require the channel to be opened with both READ and WRITE options. Assuming PRIVATE writes get saved (they don't). Writing to a READ_ONLY buffer and being surprised by `ReadOnlyBufferException`. ## Summary MapMode is the access contract for a mapping: READ_ONLY (no writes), READ_WRITE (writes hit the shared file), PRIVATE (copy-on-write, writes stay local and unsaved). The choice affects correctness, durability, and inter-process visibility.

  • If I map PRIVATE and call force(), does my change reach the file?
    No. PRIVATE is copy-on-write: modified pages become private to your process and are never written back, so force() has nothing to persist for them. Use READ_WRITE if you need durability.
  • Why does mapping READ_WRITE fail if I opened the channel with only WRITE?
    FileChannel.map() in READ_WRITE (and PRIVATE) mode requires the channel to be readable as well as writable, because the mapping must be able to read existing file contents into pages. Open it with both READ and WRITE options.

saying these in an interview costs you the question

  • Believing PRIVATE writes can be flushed to the file with force()
  • Thinking READ_WRITE only needs the channel open for writing
  • Assuming READ_ONLY mappings can be written if you cast the buffer
  • Confusing PRIVATE (copy-on-write, unsaved) with READ_WRITE (shared, saved)

context