Java
multithreading
synchronization
static variables
concurrency

How to synchronize a static variable among threads running different instances of a class in Java?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

In Java, static variables are shared among all instances of a class, as they belong to the class itself rather than any particular instance. This can present concurrency challenges when multiple threads from different instances attempt to modify a static variable at the same time. Proper synchronization is required to ensure thread safety and maintain the integrity of shared data.

Thread Safety with Static Variables

Why Synchronization?

Without synchronization, multiple threads can simultaneously read and write to a static variable, leading to race conditions, which can corrupt the data. Synchronization ensures that only one thread can modify the variable at any given time, maintaining data consistency across threads.

The Role of the synchronized Keyword

In Java, the synchronized keyword can be applied to a method or a block of code to restrict its access to a single thread at a time. When synchronizing a static method, the lock is on the class object (Class), not on the instance, since the static method can be accessed without an instance.

Synchronizing Static Variables

Consider an example class that incrementally updates a static counter, demonstrating how to synchronize access to this shared resource:

java
1public class Counter {
2    private static int count = 0;
3
4    // Synchronized static method
5    public static synchronized void increment() {
6        count++;
7    }
8
9    // Synchronized block within a static method
10    public static void safeIncrement() {
11        synchronized (Counter.class) {
12            count++;
13        }
14    }
15
16    public static int getCount() {
17        return count;
18    }
19}
20
21class CounterThread extends Thread {
22    @Override
23    public void run() {
24        for (int i = 0; i < 1000; i++) {
25            Counter.increment(); // OR Counter.safeIncrement();
26        }
27    }
28}

In this example, the increment() method is declared as synchronized, ensuring that count is thread-safe. An alternative is to use a synchronized block with the class as a lock, which allows more granular control over synchronization scope within a method.

Choosing Between Synchronized Methods and Blocks

  • Synchronized Methods: Easier to use for simple cases where the entire method needs synchronization. However, it locks the entire method, which can lead to lower concurrency.
  • Synchronized Blocks: Allow synchronization of only the critical section of code that modifies the shared resource. This can provide better performance for more complex methods by allowing non-critical sections to run concurrently.

Ensuring Visibility with volatile

While synchronization ensures atomic operations, it does not automatically ensure visibility of changes to variables across threads. This is where the volatile keyword can be useful. A volatile variable guarantees visibility by ensuring changes to the variable are immediately reflected in the main memory, and any thread reading the variable will see the most recent value.

java
1public class VolatileCounter {
2    private static volatile int count = 0;
3
4    public static synchronized void increment() {
5        count++;
6    }
7
8    public static int getCount() {
9        return count;
10    }
11}

Comparing volatile with Synchronization

Aspectvolatilesynchronized
AtomicityDoes not guarantee atomicityEnsures atomic operations
VisibilityEnsures visibilityEnsures synchronization visibility
PerformanceFaster due to no locking overheadSlower due to lock acquisition and release overhead
Use CaseFlags, states (simple read/write)Complex operations requiring atomicity (like multiple read-modify-write)

Best Practices for Synchronizing Static Variables

  1. Minimize Use of Static Variables: Whenever possible, avoid using static variables for shared data to limit concurrency issues.
  2. Use Proper Locking: Only lock the necessary code segment to enhance performance.
  3. Monitor Performance: Too much synchronization can lead to bottlenecks. Profiling can help identify performance-critical sections.
  4. Consider Higher-level Concurrency Utilities: Java’s java.util.concurrent package provides atomic classes, locks, and other utilities that can simplify managing concurrency.

Example with AtomicInteger

Instead of synchronizing access manually, the AtomicInteger class from java.util.concurrent.atomic can provide an out-of-the-box solution for thread-safe operations:

java
1import java.util.concurrent.atomic.AtomicInteger;
2
3public class AtomicCounter {
4    private static final AtomicInteger count = new AtomicInteger(0);
5
6    public static void increment() {
7        count.getAndIncrement();
8    }
9
10    public static int getCount() {
11        return count.get();
12    }
13}

Advantages of Using AtomicInteger:

  • Atomic operations for common use-cases
  • Reduced synchronization overhead
  • Simpler and clearer code

Conclusion

Synchronizing static variables across different threads is an essential practice in Java to prevent race conditions and ensure data integrity. By understanding the roles of synchronized, volatile, and advanced concurrency utilities like AtomicInteger, developers can build thread-safe applications. Proper application of these techniques can mitigate concurrency problems and enhance the reliability and performance of Java applications.


Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions