What is access-order mode in LinkedHashMap and how do you enable it?
answer
- 3-arg constructor, accessOrder = true
- Access moves entry to the tail
- Head = LRU, tail = MRU
- get counts as access; containsKey does not
- get mutates → CME risk while iterating
basics
~20 sAccess-order mode makes LinkedHashMap move an entry to the end of its list every time you read or update it, so the least-recently-used entries stay at the front. You turn it on with the three-argument constructor passing true.
solid answer
~40 sBy default LinkedHashMap orders entries by insertion. Pass `true` as the third constructor argument — `new LinkedHashMap<>(initialCapacity, loadFactor, true)` — to switch to access-order mode. Now any *access* of an entry moves it to the tail of the linked list. "Access" includes `get`, `getOrDefault`, and a `put`/`merge`/`compute` that touches an existing key; pure structural reads like `containsKey` or iterating the views do **not** count. The result is that the head of the list is always the least-recently-used entry and the tail the most-recently-used. This is the foundation for an LRU cache: combine access-order with an overridden `removeEldestEntry` to evict the head when the map exceeds a size bound. One gotcha: because `get` now structurally modifies the list, iterating while another thread (or even the same thread mid-iteration via get) mutates order can throw `ConcurrentModificationException`.
code
java · 9 lines// accessOrder = true (third arg)
LinkedHashMap<String,Integer> m =
new LinkedHashMap<>(16, 0.75f, true);
m.put("a", 1);
m.put("b", 2);
m.put("c", 3);
m.get("a"); // access 'a' -> moves it to the tail
System.out.println(m); // {b=2, c=3, a=1} -- 'a' is now most-recently-used
// head 'b' is the least-recently-used entrygo deeper
Knows there is an access-order mode enabled by a constructor flag that reorders on use.
Can enable it correctly, lists exactly which operations count as an access, and identifies head=LRU / tail=MRU.
Explains the modCount/CME interaction, thread-safety limits, and connects access-order to LRU eviction design.
Weighs access-order LinkedHashMap against dedicated cache libraries (Caffeine) on concurrency, eviction policy flexibility, and observability before choosing it for a system.
## Background A **LinkedHashMap** is a HashMap that also keeps a **doubly-linked list** (each entry has `before`/`after` pointers) running through all entries; this list decides iteration order. By default the list is in **insertion order**. ## The third constructor argument LinkedHashMap has a constructor `LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder)`. The boolean `accessOrder` is the switch: - `false` (the default, and what the simpler constructors use) → **insertion-order** mode. - `true` → **access-order** mode. ## What access-order does In access-order mode, every time an entry is **accessed**, LinkedHashMap unlinks it from its current spot and re-appends it at the **tail** of the list. "Accessed" means: - `get(key)` / `getOrDefault(key, ...)` that finds the key, - `put(key, value)` / `putIfAbsent` / `merge` / `compute*` that operates on an **existing** key, - `replace(key, ...)`. It does **not** include `containsKey`, `containsValue`, `size`, or iterating `keySet`/`entrySet`/`values` — those are reads that leave order alone. (Note `getOrDefault` *does* count as an access if the key is present.) Consequence: the **head** (front) of the list is always the entry accessed longest ago — the **least-recently-used (LRU)** — and the **tail** is the **most-recently-used (MRU)**. That ordering is exactly what an LRU cache needs. ## Why this matters Access-order mode is the engine behind a bounded LRU cache: you keep the most-recently-used items near the tail and evict from the head. You typically pair it with overriding `removeEldestEntry` (covered in its own question) so the map auto-evicts the eldest (head) entry once it grows past a capacity limit. ## Pitfalls 1. **`get` mutates structure.** Because a successful `get` reorders the list, it increments the map's internal `modCount`. If you call `get` while iterating the same map, you can trigger a `ConcurrentModificationException` even though you only "read". 2. **Not thread-safe.** Concurrent reads can race because reads now write. Wrap with `Collections.synchronizedMap` plus external synchronization on iteration, or use a purpose-built concurrent cache (e.g., Caffeine) instead. 3. **`putAll` / view operations** follow the same access rules per element.
- Does calling containsKey reorder the list in access-order mode?No. Only true 'accesses' — get/getOrDefault and put/merge/compute on an existing key — move an entry to the tail. containsKey, size, and iteration leave order untouched.
- Why can a plain get throw ConcurrentModificationException in access-order mode?Because a successful get reorders the linked list, which bumps the map's modCount. If that happens during iteration, the iterator's fail-fast check detects the modification and throws.
Think of a stack of papers on a desk in access-order mode: every time you pick up and use a sheet, you put it back on top. The sheet at the very bottom is the one you haven't touched in the longest time — the first you'd throw away if the desk got too full.
saying these in an interview costs you the question
- Saying you enable access order with a method call like setAccessOrder() — it is only settable via the constructor and is final thereafter.
- Claiming containsKey or iteration reorders entries — they do not.
- Thinking the head is the most-recently-used — it is the least-recently-used.
- Assuming access-order LinkedHashMap is safe to share across threads for reads.