Thread interference in Java refers to the situation where two or more threads access shared data or resources concurrently without proper synchronization, leading to unexpected and erroneous behavior. This issue arises due to the non-atomicity of operations involving shared resources, where an interleaving of operations from multiple threads can result in inconsistent or incorrect state.
To avoid thread interference and ensure correct behavior when multiple threads access shared resources concurrently, you can use synchronization mechanisms such as synchronized
methods, synchronized
blocks, ReentrantLock
, or atomic variables (AtomicInteger
, AtomicLong
, etc.). These mechanisms ensure that only one thread can access the shared resource at a time, preventing interleaved operations that lead to inconsistencies.
Consider a simple counter class that is not thread-safe:
//ThreadInterferenceDemo.java class Counter { private int count = 0; public void increment() { // Non-atomic operation int temp = count; temp = temp + 1; count = temp; } public int getCount() { return count; } } public class ThreadInterferenceDemo { public static void main(String[] args) throws InterruptedException { Counter counter = new Counter(); // Thread 1 increments the counter 1000 times Thread thread1 = new Thread(() -> { for (int i = 0; i < 1000; i++) { counter.increment(); } }); // Thread 2 increments the counter 1000 times Thread thread2 = new Thread(() -> { for (int i = 0; i < 1000; i++) { counter.increment(); } }); // Start both threads thread1.start(); thread2.start(); // Wait for both threads to finish thread1.join(); thread2.join(); // Expected count after both threads finish (should be 2000) System.out.println("Final Count: " + counter.getCount()); // May not be 2000 due to thread interference } } /* C:\>javac ThreadInterferenceDemo.java C:\>java ThreadInterferenceDemo Final Count: 2000 C:\>java ThreadInterferenceDemo Final Count: 1974 C:\>java ThreadInterferenceDemo Final Count: 2000 C:\>java ThreadInterferenceDemo Final Count: 1889 C:\>java ThreadInterferenceDemo Final Count: 2000 */
Here’s an example of using synchronized
methods to make the Counter
class thread-safe:
//SynchronizedThreadInterferenceDemo.java class Counter { private int count = 0; public synchronized void increment() { // Non-atomic operation int temp = count; temp = temp + 1; count = temp; } public synchronized int getCount() { return count; } } public class SynchronizedThreadInterferenceDemo { public static void main(String[] args) throws InterruptedException { Counter counter = new Counter(); // Thread 1 increments the counter 1000 times Thread thread1 = new Thread(() -> { for (int i = 0; i < 1000; i++) { counter.increment(); } }); // Thread 2 increments the counter 1000 times Thread thread2 = new Thread(() -> { for (int i = 0; i < 1000; i++) { counter.increment(); } }); // Start both threads thread1.start(); thread2.start(); // Wait for both threads to finish thread1.join(); thread2.join(); // Expected count after both threads finish (should be 2000) System.out.println("Final Count: " + counter.getCount()); // May not be 2000 due to thread interference } } /* C:\>java SynchronizedThreadInterferenceDemo Final Count: 2000 C:\>java SynchronizedThreadInterferenceDemo Final Count: 2000 C:\>java SynchronizedThreadInterferenceDemo Final Count: 2000 */
Thread interference is a critical issue in concurrent programming where shared resources are accessed by multiple threads without proper synchronization. Understanding and addressing thread interference is essential to ensure correct and reliable behavior in multi-threaded applications.