Backend Development 15 min read

Mastering Java Locks: From Optimistic to Fairness and JVM Optimizations

This article provides a comprehensive overview of Java lock mechanisms—including optimistic, pessimistic, reentrant, fair, unfair, read/write, spin, and JVM-level optimizations—illustrated with clear explanations, code snippets, and performance‑tuning tips for high‑concurrency applications.

Xiaokun's Architecture Exploration Notes
Xiaokun's Architecture Exploration Notes
Xiaokun's Architecture Exploration Notes
Mastering Java Locks: From Optimistic to Fairness and JVM Optimizations

Lock Types

In concurrent environments, locks are classified mainly as optimistic and pessimistic.

Optimistic lock : Assumes low contention; before writing, it checks whether the current version matches the previously read version. If not, the operation is retried. Examples include CAS mechanisms, Zookeeper leader election, and version‑based database updates.

Pessimistic lock : Assumes high contention; acquires the lock before entering the critical section and releases it after the operation, causing other threads to block.

Example pseudo‑code for both approaches is shown below.

<code>// optimistic.java
AtomicInteger count = new AtomicInteger();
run(){
    int expected = 10;
    int updated = 12;
    count.compareAndSet(expected, updated);
    // DB example
    Object row = selectById();
    row.setXX();
    updateRowByIdWithVersion(row);
}

// pessimistic.java
run(){
    synchronized(this){
        // critical code
    }
    // DB lock example
    db.execute("select * from tb_entity where id=#{id} for update");
    db.execute("update tb_entity set x1=?,... where id=#{id}");
}
</code>

Reentrant and Recursive Locks

A reentrant lock allows the same thread to acquire the lock multiple times, enabling recursive method calls. In Java, ReentrantLock and the synchronized keyword provide this capability.

<code>final static ReentrantLock reentrantLock = new ReentrantLock();
run(){
    reentrantLock.lock();
    // ...
    reentrantLock.lock(); // re‑enter
    // ...
    reentrantLock.unlock();
    reentrantLock.unlock();
}

synchronized void createOutBoundOrder(){
    // ...
}
</code>

Fair and Unfair Locks

Fair locks grant access in FIFO order, while unfair locks allow threads to “cut in line,” leading to nondeterministic acquisition order. Java implements fairness via the ReentrantLock(boolean fair) constructor.

<code>// Fair lock (may impact performance)
ReentrantLock pairLock = new ReentrantLock(true);

// Unfair lock (default)
ReentrantLock unpairLock = new ReentrantLock(false);
</code>

Shared (Read) and Exclusive (Write) Locks

Read locks allow multiple threads to read simultaneously, whereas write locks are exclusive. Java’s ReentrantReadWriteLock provides this functionality.

<code>private static void readWriteLock(){
    final Lock read = reentrantReadWriteLock.readLock();
    final Lock write = reentrantReadWriteLock.writeLock();
    for(int i=0;i<10;i++){
        new Thread(){
            public void run(){
                try{ read.lock(); read(); } finally { read.unlock(); }
            }
        }.start();
        new Thread(){
            public void run(){
                try{ write.lock(); write(); } finally { write.unlock(); }
            }
        }.start();
    }
}
</code>

Spin Lock (CAS + Loop)

A spin lock repeatedly attempts to acquire a lock using CAS without blocking the thread. In Java, the spin count can be tuned with the JVM option -XX:PreBlockSpinsh . Example implementation:

<code>private static Unsafe unsafe;
private static long valueOffset;
private volatile int count = 0;
static{
    try{
        Field f = Unsafe.class.getDeclaredField("theUnsafe");
        f.setAccessible(true);
        unsafe = (Unsafe)f.get(null);
        valueOffset = unsafe.objectFieldOffset(LockCASDemo.class.getDeclaredField("count"));
    }catch(Exception e){ e.printStackTrace(); }
}
private void countAdder(){
    int current, value;
    do{
        current = unsafe.getIntVolatile(this, valueOffset);
        value = current + 1;
    }while(!unsafe.compareAndSwapInt(this, valueOffset, current, value));
}
</code>

JVM Lock Optimizations

Lock biasing : The object header stores the thread ID that first acquires the lock.

Lightweight lock : When contention rises, the lock upgrades to a lightweight lock using CAS on the object header.

Heavyweight (mutex) lock : Under heavy contention, the lock inflates to a heavyweight monitor, which cannot be downgraded.

Reference: synchronized Working Principle (Part 3)

Reducing Lock Hold Time

Only lock when thread‑safety is required and keep the critical section as short as possible. Example:

<code>run(){
    try{
        lock.lock();
        // create order items, orders, outbound orders
    }finally{
        lock.unlock();
    }
}
</code>

Lock Coarsening

Repeatedly acquiring and releasing the same lock in a tight loop wastes CPU cycles. Coarsening merges adjacent critical sections into a single lock acquisition.

<code>// Before coarsening
synchronized(this){ productNum--; }
// ... other work ...
synchronized(this){ orderItem++; }

// After coarsening
synchronized(this){
    productNum--;
    orderItem++;
}
</code>

Lock Elimination

The JIT compiler removes locks that protect non‑shared (thread‑private) data, as they are unnecessary.

<code>// Pseudo‑code
Object obj = new Object();
int count = 0;
synchronized(obj){
    count++;
}
// JIT eliminates the synchronized block because obj is thread‑local.
</code>

Lock Granularity (Sharding)

Reducing lock scope improves concurrency. For example, ConcurrentHashMap locks individual segments, and databases can use row‑level locks instead of table‑level locks.

Lock Separation

Separate read and write paths using ReadWriteLock so that reads can proceed concurrently while writes remain exclusive.

JavaJVMConcurrencySynchronizationLocksOptimisticLockPessimisticLock
Xiaokun's Architecture Exploration Notes
Written by

Xiaokun's Architecture Exploration Notes

10 years of backend architecture design | AI engineering infrastructure, storage architecture design, and performance optimization | Former senior developer at NetEase, Douyu, Inke, etc.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.