skip to content

If one thread assigns an object reference to a field while another thread reads that field, can the reader ever observe a half-written, invalid reference — for instance on a 64-bit JVM where a pointer is eight bytes wide?

level: juniorimportance: should knowfreq 35%

answer

  1. Reference reads/writes always atomic — no long/double-style exception
  2. Torn pointer would break memory safety, so it cannot be allowed
  3. Compressed oops: 32-bit encoding, still atomic
  4. Atomic ≠ timely: stale or null reads still possible
  5. Whole reference ≠ fully observable object

basics

~20 s

No. The Java Language Specification guarantees that reference reads and writes are atomic regardless of pointer width, so the reader sees either the old reference or the new one, never a mixture. It does not guarantee the reader sees the new one promptly, or sees the object fully initialised.

solid answer

~60 s

Reference assignment is atomic by specification — unlike `long` and `double`, references have no non-atomic escape clause. Whatever the pointer width (32-bit, 64-bit, or a compressed 32-bit encoding of a 64-bit address in HotSpot), a reader observes exactly one complete reference value: the previous one or the newly stored one. Nothing in between is observable, which is essential, since a torn pointer would be a wild address and would break the platform's memory safety outright. Two caveats matter and interviewers look for them: 1. **Atomicity is not visibility.** Without synchronisation, the reading thread may keep seeing the old reference indefinitely; there is no promise about *when* the new value shows up. 2. **An intact reference does not imply an intact object.** Seeing the new reference says nothing about whether the object's fields are observable in their initialised state — publishing an object safely is a separate guarantee that requires synchronisation (or final fields). So the honest answer is: the pointer itself is never torn; everything else about the handover needs more than atomicity.

code

java · 11 lines
java
class Holder {
    Config cfg;                 // plain field

    void publish() { cfg = new Config(load()); } // the reference write is atomic

    void use() {
        Config c = cfg;         // sees old ref or new ref — never a torn pointer
        if (c != null) c.apply(); // but may be stale, and c's fields are not
                                  // guaranteed observable as fully constructed
    }
}

go deeper

for a junior

Answer plainly: reference reads and writes are atomic, so you never see a half-written pointer — only the old value or the new one.

for a middle

Add the memory-safety rationale and note that atomicity of the pointer says nothing about visibility timing.

for a senior

Volunteer the second caveat — an intact reference does not imply the referenced object's state is reliably observable — and connect it to why publication rules exist separately.

for a principal

Position it as a design property of a managed runtime: guaranteed pointer integrity converts a class of memory-corruption bugs into logic bugs, which changes how you triage and contain concurrency defects.

## The direct answer No. The Java Language Specification states that reads and writes of *reference* variables are always atomic. The exception it carves out for non-atomic treatment applies only to `long` and `double`; references are not in it, whatever their machine representation. So for `this.node = newNode;`, any concurrent reader of `node` observes either the reference that was there before or the reference just stored. There is no third possibility — no half-old, half-new bit pattern. ## Why the platform cannot afford to do otherwise This guarantee is not a convenience; it is load-bearing for memory safety. A reference is an address (or an encoding of one). A torn reference would be an address that no allocation ever occupied — pointing into the middle of an object, past the end of the heap, or at unmapped memory. Dereferencing it would produce arbitrary memory corruption or a process crash, with no Java-level exception in sight, and the language's core promise that you cannot forge a pointer would be gone. That is also why the guarantee holds no matter how the implementation represents references. HotSpot on a 64-bit machine commonly uses **compressed ordinary object pointers**: a 32-bit value scaled and offset to address a heap up to roughly 32 GB, which reduces footprint and improves cache behaviour. Whether the field holds four bytes or eight, the store is a single aligned machine access and is atomic. A garbage collector that moves objects has to preserve the same property — an application thread must never observe a partially updated reference while the collector relocates the target — which is one of the things read and write barriers in concurrent collectors exist to ensure. ## Caveat one: atomic is not visible A very common mistake is to reason: "reference writes are atomic, therefore publishing an object by assigning it to a field is thread-safe." Atomicity says the *value* cannot be observed in pieces. It says nothing about *when* another thread observes it. In an unsynchronised program, the reader may continue reading a stale reference — including `null` — for an unbounded time, because nothing has established the required ordering relationship between the writing thread and the reading thread. The fix is ordinary synchronisation: `volatile`, a lock held by both threads, or one of the many library mechanisms that carry the same guarantee. ## Caveat two: an intact reference is not an intact object The subtler point, and the one that separates a solid answer from a shallow one. Consider: ```java shared = new Config(values); // construct, then assign ``` The reference the reader sees is guaranteed whole. What the reader may see through it is a different matter: without appropriate synchronisation, the object's fields are not guaranteed to be observed in their fully constructed state. "I got a valid, non-null reference" therefore does not license "the object behind it is fully built as far as I am concerned." Making an object safely available to other threads is a separate concern with its own rules; it is not something reference atomicity provides. So the two failure modes to keep distinct are: - *Torn reference* — impossible in Java, by specification. - *Reference visible but object state not reliably observable* — entirely possible in an unsynchronised program, and the reason publication rules exist. ## Practical consequences - **Reading a reference field without synchronisation cannot crash the JVM.** You may get a stale value or `null`, and you may then get a `NullPointerException` — but never a corrupt pointer. That is why the failure mode of racy Java code is "wrong answer" rather than "segfault", which is a genuine advantage over unmanaged languages. - **Nullability checks on racy reads are not enough.** `if (ref != null) ref.use();` can pass the check and then act on an object whose state was not properly published, or on a value that has since changed. Atomicity of the read does not make the sequence safe. - **Do not assume compressed pointers change anything.** Compressed-oops settings affect footprint and the addressable heap, not atomicity. ## How to pitch it Answer "no" immediately, justify it with the specification's rule and the memory-safety argument, mention that pointer width and compressed representations do not change it, and then volunteer the two caveats: atomicity is not visibility, and a whole reference does not imply a fully observable object. That last sentence is what makes the answer sound like experience rather than recall.

  • If reference assignment is atomic, why is publishing an object by a plain field write still not safe?
    Because atomicity only guarantees the pointer value is never observed in pieces. It gives no guarantee about when the reader sees the new reference, and none about the state of the object it points at being observable as fully constructed. Handing an object to another thread correctly requires synchronisation that establishes ordering, not just an indivisible pointer store.
  • Does HotSpot's compressed-pointer representation affect the atomicity guarantee?
    No. Compressed ordinary object pointers store a reference as a 32-bit scaled value to shrink footprint and improve cache behaviour on heaps up to roughly 32 GB. Whether a reference occupies four or eight bytes, the field access is a single aligned machine access and remains atomic, so the language guarantee is unaffected by the encoding.
  • What is the worst that can happen when a Java program reads a reference field with a data race?
    It can read a stale value, including `null`, and act on it — leading to a `NullPointerException` or logically wrong behaviour, and possibly to using an object whose state it cannot rely on. What it cannot do is obtain an invalid pointer and corrupt memory, because reference reads and writes are atomic and the runtime is memory-safe.

saying these in an interview costs you the question

  • Claiming references can tear on 64-bit platforms because pointers are 8 bytes
  • Concluding that because reference writes are atomic, publishing an object needs no synchronisation
  • Believing a racy reference read can crash the JVM or corrupt memory
  • Thinking compressed pointers weaken or strengthen the atomicity guarantee
  • Treating a non-null check on a racy read as sufficient for correctness

context