Understanding the “Hardest” Java Interview Question and Thread‑Safety Fundamentals
This article presents a notoriously tricky Java interview problem, walks through its multithreaded code, explains the possible outputs, and then expands into a comprehensive discussion of thread‑safety concepts, synchronization mechanisms, and best practices for writing safe concurrent Java programs.
The article begins by introducing a so‑called "hardest" Java interview question that challenges readers to reason about thread safety and predict the program's output.
public class TestSync2 implements Runnable { int b = 100; synchronized void m1() throws InterruptedException { b = 1000; Thread.sleep(500); //6 System.out.println("b=" + b); } synchronized void m2() throws InterruptedException { Thread.sleep(250); //5 b = 2000; } @Override public void run() { try { m1(); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) throws InterruptedException { TestSync2 tt = new TestSync2(); Thread t = new Thread(tt); //1 t.start(); //2 tt.m2(); //3 System.out.println("main thread b=" + tt.b); //4 } }
The author encourages readers to attempt solving the problem before seeing the answer, noting common misconceptions such as confusing .start() with .run() and overlooking the effects of synchronized blocks and Thread.sleep() .
Possible outputs are discussed, showing that depending on thread scheduling the main thread may print b=2000 or b=1000 , while the worker thread always prints b=1000 . The article then presents the correct answer and explains the reasoning behind each case.
Following the interview question, the piece shifts to a broader tutorial on thread safety. It defines thread safety using a quote from "Java Concurrency in Practice" and outlines the environment (multiple threads), the operation (concurrent execution), and the desired outcome (correct results without extra synchronization).
The author categorises thread‑safety levels into five groups:
Immutable – inherently thread‑safe.
Absolutely thread‑safe – strict definition from Brian Goetz.
Relatively thread‑safe – safe for individual operations but may need external synchronization for compound actions.
Thread‑compatible – not thread‑safe by itself but can be made safe by the caller (e.g., locking an ArrayList ).
Thread‑hostile – cannot be used safely in concurrent contexts.
Examples are provided, such as a Vector get/remove race condition and how adding synchronized to the methods can turn it into relatively safe code.
The article then describes common strategies for achieving thread safety:
Mutual exclusion (synchronized or ReentrantLock) – the preferred approach in most Java code.
Non‑blocking synchronization (CAS) – optimistic technique using compareAndSwap methods.
No synchronization – when code is re‑entrant or uses thread‑local storage.
Practical advice follows, covering topics such as avoiding deadlocks, choosing appropriate lock granularity, using immutable objects (e.g., String , enum ), replacing non‑thread‑safe collections with concurrent alternatives, and leveraging ThreadLocal for thread‑confined data.
Finally, the author encourages further reading of Zhou Zhiming’s "Deep Understanding of the JVM" chapter on thread safety and invites feedback on any mistakes.
Architecture Digest
Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.