Thread safety of static blocks in Java
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
Java static initializer blocks are thread-safe during class initialization, but that guarantee is often misunderstood. The JVM ensures one-time synchronized initialization per class loader. After initialization, normal concurrency rules still apply to any mutable static state.
JVM Guarantee for Class Initialization
When a class is first actively used, JVM runs class initialization before allowing regular access. Only one thread executes initialization for that class while other threads wait.
Active use includes:
- reading or writing a static field
- invoking a static method
- creating an instance
AppConfig static block runs once per class loader.
Initialization Safety Is Not Ongoing Mutation Safety
A frequent mistake is assuming static data remains thread-safe because it was initialized safely. That is false for mutable objects.
Unsafe example:
Concurrent writes to this map are unsafe despite safe initialization.
Use Concurrent Structures for Shared Static State
If static state is mutable and shared, use concurrency-aware collections.
This protects runtime updates after initialization completes.
Keep Static Initialization Lightweight
Static blocks should avoid heavy I O and remote calls. Expensive initialization increases startup latency and can fail in unpredictable ways.
Good static-block candidates:
- constants
- immutable maps
- light local setup
Immutable static data reduces concurrency risk significantly.
Lazy Initialization with Holder Idiom
For expensive setup needed only on demand, use initialization-on-demand holder.
This keeps lazy behavior while using JVM class initialization guarantees.
Class Loader Nuance
The one-time guarantee is per class loader. In application servers or plugin systems, the same class can initialize once in each loader context. This matters when diagnostics seem to show repeated static initialization.
Log class loader identity during debugging if initialization appears to run more than once unexpectedly.
Quick Concurrency Validation
A simple test can confirm one-time initialization behavior.
Initialization log should appear once for that loader.
Common Pitfalls
- Assuming static initialization safety means mutable static fields are always thread-safe.
- Performing slow network work in static blocks.
- Catching and suppressing static initialization exceptions.
- Using non-concurrent collections for shared static mutation.
- Ignoring class loader boundaries in container environments.
Summary
- Java static blocks are thread-safe for one-time class initialization.
- The guarantee applies per class loader, not globally forever.
- Mutable static state still needs proper concurrency controls.
- Keep static initialization fast and deterministic.
- Use holder idiom for lazy initialization when needed.
Related reading
- Thread vs. Threading
- Thread vs ThreadPool
- Thread vs ThreadPool
- Threading Example in Android
- ThreadPoolExecutor Block When its Queue Is Full?
- ThreadPoolExecutor with corePoolSize 0 should not execute tasks until task queue is full
- Threading in a PyQt application Use Qt threads or Python threads?
- Threading in Python

OOD Fundamentals
Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.
View the courseTrack 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.