Java
Constructor Synchronization
Multithreading
Thread Safety
Java Concurrent Programming

Constructor synchronization in Java

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Java constructors cannot be marked with synchronized, which is often confusing when developers are learning thread safety. Constructor safety is achieved through safe publication rules, immutable state, and controlled object visibility. The important goal is not locking the constructor, but preventing partially constructed objects from becoming visible to other threads.

Why Constructors Are Not synchronized

The synchronized keyword applies to methods and code blocks, not constructors. During construction, object identity exists but state may still be incomplete. If object reference escapes during that phase, other threads can observe inconsistent values.

So constructor safety is mostly about publication discipline.

Use Immutable State and Final Fields

Final fields give strong visibility guarantees after successful construction.

java
1public final class AppConfig {
2    private final String host;
3    private final int port;
4
5    public AppConfig(String host, int port) {
6        this.host = host;
7        this.port = port;
8    }
9
10    public String getHost() { return host; }
11    public int getPort() { return port; }
12}

Immutable objects drastically reduce synchronization requirements.

Avoid this Escape in Constructors

Never publish this from constructor. Typical bad patterns include listener registration, starting threads, or storing this in shared static collections.

java
1public class BadService {
2    public BadService(Registry registry) {
3        registry.register(this); // unsafe publication during construction
4    }
5}

Prefer factory or initialization method that publishes object only after construction completes.

Synchronize Mutable Operations Instead

If object has mutable shared state, synchronize the state-changing methods or use explicit locks.

java
1public class Counter {
2    private int value;
3
4    public synchronized void increment() {
5        value++;
6    }
7
8    public synchronized int get() {
9        return value;
10    }
11}

This targets synchronization where concurrency happens, not where object is allocated.

Safe Publication Patterns

Common safe publication approaches:

  • Store reference in a properly synchronized field.
  • Publish through thread-safe collection.
  • Assign to volatile field.
  • Publish as static final during class initialization.

These patterns ensure other threads see fully initialized state.

Lazy Initialization and Double-Checked Locking

Singleton patterns often trigger constructor synchronization questions. The correct locking point is accessor path, not constructor.

java
1public class Singleton {
2    private static volatile Singleton instance;
3
4    private Singleton() {}
5
6    public static Singleton getInstance() {
7        if (instance == null) {
8            synchronized (Singleton.class) {
9                if (instance == null) {
10                    instance = new Singleton();
11                }
12            }
13        }
14        return instance;
15    }
16}

volatile is required so initialized object state is visible correctly across threads.

Factory Pattern for Controlled Lifecycle

Factories can enforce creation, initialization, and publication order.

java
1public final class ServiceFactory {
2    public static Service create(Registry registry) {
3        Service service = new Service();
4        service.initialize();
5        registry.register(service);
6        return service;
7    }
8}

This avoids unsafe publication from constructor and keeps lifecycle explicit.

Test Concurrency Assumptions

Thread safety is easy to assume and hard to prove. Add tests that run critical code paths concurrently and validate invariants.

In addition to unit tests, use stress tests under load to catch race conditions that do not appear in short runs.

Concurrency bugs are often timing-sensitive, so repeated runs in CI can reveal failures early.

Common Pitfalls

  • Trying to declare constructors as synchronized methods.
  • Publishing this before construction is complete.
  • Assuming immutability while exposing mutable internal state.
  • Using double-checked locking without volatile.
  • Skipping concurrency tests for classes used across threads.

Summary

  • Java constructors are not synchronized and do not need to be.
  • Safe construction relies on final fields and safe publication.
  • Prevent this escape during object creation.
  • Synchronize mutable shared behavior at method or block level.
  • Use factories and concurrency tests to keep lifecycle thread-safe.

Course illustration
Course illustration

All Rights Reserved.