You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Integer静态对象作为锁时线程同步失效的原因

Why Using Integer as a Lock Causes IllegalMonitorStateException (and Fixes)

Great question! Let's walk through exactly what's going wrong with your original code, and why switching to a static Object lock fixes the issues you're seeing.

The Root Cause: Integer's Immutability Breaks Lock Consistency

The core problem here is that Integer is an immutable class, and you're using it both as your synchronization lock and your counter variable. This combination creates a hidden issue where your lock object gets silently replaced mid-execution, triggering IllegalMonitorStateException and breaking thread coordination.

Let's break down the step-by-step issue in your code:

  • Lock Acquisition: When a thread enters synchronized(counter), it acquires the lock on the specific Integer instance that counter points to (initially the instance holding the value 2).
  • counter++ Changes the Lock: counter++ doesn't modify the existing Integer object (immutable classes can't be changed after creation). Instead, it does something like counter = Integer.valueOf(counter.intValue() + 1)—this creates a new Integer instance (or reuses a cached one, but the reference still changes) and updates the counter variable to point to this new object.
  • notify() Fails Due to Mismatched Lock: When you call counter.notify() later, your thread still holds the lock on the original Integer instance (the one with value 2), but counter now points to a completely different object (e.g., value 3). Since you don't hold the lock on this new object, calling notify() on it throws IllegalMonitorStateException.

This lock mismatch also explains the unstable output and missing "Complete" message: the broken wait/notify logic means threads can get stuck waiting forever, so your t1.join() and t2.join() might never complete.

Why a Static Object Lock Works

When you switch to using static Object lock as your synchronization target:

  • The lock variable always points to the same Object instance—you never modify this reference, only update the separate counter variable.
  • Every time you enter synchronized(lock), you're acquiring the lock on the exact same object. Calling lock.wait() and lock.notify() is always valid because your thread holds the lock on that object.
  • Thread coordination works as expected: even threads wait and wake each other correctly, both threads finish their loops, and your main thread's join() calls complete, so "Complete" prints reliably.

A Quick Note on Integer Caching

You might wonder: since Integer caches values from -128 to 127, does that change anything? Nope—even if counter++ reuses a cached instance, the counter reference still switches to a different object. The lock is tied to the object instance, not its value, so switching references breaks the lock consistency regardless of caching.

Fix Recommendations

Beyond using a static Object lock, here are a couple other approaches:

  • Separate Counter and Lock: Always keep your counter variable and synchronization lock as separate entities. Never use an immutable object as a lock unless you can guarantee its reference will never change.
  • Use AtomicInteger for Counting: If you want to avoid manual synchronization for the counter itself, use AtomicInteger—but you'll still need a separate lock object for the wait/notify logic, since atomic operations don't handle thread waiting.

内容的提问来源于stack exchange,提问作者kalpesh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 10:47:48