Java线程间共享Integer变量的问题咨询及解决方法
Hey there, let's break down why you're hitting issues sharing an Integer across threads—even when you've thought about critical sections. The root of the problem boils down to two key things: Integer's immutability and thread visibility guarantees. Let's walk through the fixes step by step.
Why Your Current Approach Isn't Working
First, let's clarify a critical detail: Integer is an immutable class. When you do something like count++, you're not modifying the existing Integer object—you're creating a brand new Integer instance with the incremented value. If your threads are holding onto the old Integer reference, they'll never see the new value, even if you've got locks around the operation.
Even if you fixed the reference issue, you'd still have to worry about visibility: threads might cache the value locally, so changes from one thread won't show up in others unless you enforce memory consistency.
Recommended Solutions
1. Use AtomicInteger (Best Practice)
This is the cleanest, most efficient way to handle a thread-safe mutable integer. AtomicInteger from java.util.concurrent.atomic handles both atomic operations (like increment) and visibility out of the box, using low-level CAS (Compare-And-Swap) operations instead of heavy locks.
Here's a quick example:
import java.util.concurrent.atomic.AtomicInteger; public class SharedCounter { // Initialize with your starting value private final AtomicInteger sharedCount = new AtomicInteger(0); // Worker threads call this to increment public void incrementCount() { sharedCount.incrementAndGet(); } // Main thread or other threads call this to get the latest value public int getCurrentCount() { return sharedCount.get(); } }
incrementAndGet()atomically increments the value and returns the new count.- The internal
valuefield is markedvolatile, so all threads see the latest value immediately.
2. Create a Custom Mutable Container
If you prefer not to use the atomic utilities, you can wrap a primitive int in a custom class, then use volatile for visibility and synchronized for atomicity:
public class MutableIntCounter { // Volatile ensures changes are visible across threads private volatile int count; public MutableIntCounter(int initialValue) { this.count = initialValue; } // Synchronized ensures the read-modify-write operation is atomic public synchronized void increment() { count++; } public synchronized int getCount() { return count; } }
volatiletells the JVM not to cache thecountvalue locally in threads.synchronizedlocks the method, so only one thread can modify or read the value at a time, preventing race conditions.
3. Hacky Fix with volatile Integer (Not Recommended)
If you absolutely must use Integer (though I'd advise against it), you can mark the Integer reference as volatile and use a lock to ensure atomicity of the increment. But remember—you're still creating a new Integer instance every time you modify it, which is inefficient:
public class SharedIntegerWrapper { private volatile Integer count = 0; private final Object lock = new Object(); public void increment() { synchronized (lock) { // Creates a new Integer instance each time count = count + 1; } } public Integer getCount() { return count; } }
This works, but it's clunky and unnecessary when AtomicInteger exists.
Final Notes
- Always prioritize
AtomicIntegerfor thread-safe integer operations—it's designed exactly for this use case. - Avoid using raw
Integerfor shared mutable state; its immutability will lead to subtle bugs that are hard to track down. - If you're using locks, make sure all threads that access the shared variable use the same lock object to avoid race conditions.
内容的提问来源于stack exchange,提问作者Marta G.

