Fundamentals 11 min read

Pessimistic and Optimistic Locks in Java: Theory and Code Examples

The article compares Java's pessimistic locking mechanisms such as synchronized blocks and ReentrantLock with optimistic approaches like version checks, CAS‑based AtomicInteger and custom spin locks, illustrating each method through counter examples and discussing their performance trade‑offs and limitations.

Java Tech Enthusiast
Java Tech Enthusiast
Java Tech Enthusiast
Pessimistic and Optimistic Locks in Java: Theory and Code Examples

In multithreaded environments, Java programs can encounter thread‑safety issues. Java provides synchronization mechanisms such as synchronized and Lock to address them.

Pessimistic vs. Optimistic Locks

Pessimistic locks assume the worst case: every data access is locked, preventing other threads from modifying the data until the lock is released. Examples include database table/row locks and Java’s synchronized or ReentrantLock .

Optimistic locks assume the best case: data is read without locking, and a version check is performed before committing changes. If the version has changed, the update fails and must be retried. Common techniques are version fields, CAS (compare‑and‑swap), and AtomicInteger .

Code Example – Unsynchronized Counter

public class LockDemo {
    static int count = 0;
    public static void main(String[] args) throws InterruptedException {
        List
threadList = new ArrayList<>();
        for (int i = 0; i < 50; i++) {
            Thread thread = new Thread(() -> {
                for (int j = 0; j < 1000; ++j) {
                    count++;
                }
            });
            thread.start();
            threadList.add(thread);
        }
        for (Thread thread : threadList) {
            thread.join();
        }
        System.out.println(count);
    }
}

Running this program typically prints a value far below 50000 because of race conditions.

Using synchronized

public class LockDemo {
    static int count = 0;
    public static void main(String[] args) throws InterruptedException {
        List
threadList = new ArrayList<>();
        for (int i = 0; i < 50; i++) {
            Thread thread = new Thread(() -> {
                // 使用synchronized关键字解决线程安全问题
                synchronized (LockDemo.class) {
                    for (int j = 0; j < 1000; ++j) {
                        count++;
                    }
                }
            });
            thread.start();
            threadList.add(thread);
        }
        for (Thread thread : threadList) {
            thread.join();
        }
        System.out.println(count);
    }
}

The synchronized block guarantees the final result of 50000 .

Using ReentrantLock

public class LockDemo {
    static int count = 0;
    public static void main(String[] args) throws InterruptedException {
        List
threadList = new ArrayList<>();
        Lock lock = new ReentrantLock();
        for (int i = 0; i < 50; i++) {
            Thread thread = new Thread(() -> {
                // 使用ReentrantLock关键字解决线程安全问题
                lock.lock();
                try {
                    for (int j = 0; j < 1000; ++j) {
                        count++;
                    }
                } finally {
                    lock.unlock();
                }
            });
            thread.start();
            threadList.add(thread);
        }
        for (Thread thread : threadList) {
            thread.join();
        }
        System.out.println(count);
    }
}

Both approaches implement pessimistic locking.

Optimistic Lock with Version Field

In a database table, a version column is checked and incremented atomically. If two threads try to update the same row, only the first succeeds; the second detects a version mismatch and must retry.

CAS with AtomicInteger

public class LockDemo {
    static AtomicInteger count = new AtomicInteger(0);
    public static void main(String[] args) throws InterruptedException {
        List
threadList = new ArrayList<>();
        for (int i = 0; i < 50; i++) {
            Thread thread = new Thread(() -> {
                for (int j = 0; j < 1000; ++j) {
                    // 使用AtomicInteger解决线程安全问题
                    count.incrementAndGet();
                }
            });
            thread.start();
            threadList.add(thread);
        }
        for (Thread thread : threadList) {
            thread.join();
        }
        System.out.println(count);
    }
}

CAS repeatedly reads the current value and attempts to replace it with value+1 using compareAndSwapInt . If another thread modifies the value in the meantime, the operation retries, forming a spin‑lock style optimistic lock.

Custom Spin Lock

public class LockDemo {
    private AtomicReference
atomicReference = new AtomicReference<>();
    public void lock() {
        // 获取当前线程对象
        Thread thread = Thread.currentThread();
        // 自旋等待
        while (!atomicReference.compareAndSet(null, thread)) {
        }
    }
    public void unlock() {
        // 获取当前线程对象
        Thread thread = Thread.currentThread();
        atomicReference.compareAndSet(thread, null);
    }
    static int count = 0;
    public static void main(String[] args) throws InterruptedException {
        LockDemo lockDemo = new LockDemo();
        List
threadList = new ArrayList<>();
        for (int i = 0; i < 50; i++) {
            Thread thread = new Thread(() -> {
                lockDemo.lock();
                for (int j = 0; j < 1000; j++) {
                    count++;
                }
                lockDemo.unlock();
            });
            thread.start();
            threadList.add(thread);
        }
        // 等待线程执行完毕
        for (Thread thread : threadList) {
            thread.join();
        }
        System.out.println(count);
    }
}

The spin lock uses an AtomicReference<Thread> to acquire ownership; other threads spin until the lock is released.

While optimistic locks reduce context switches, they may waste CPU cycles, are limited to single‑variable atomicity, and can suffer from the ABA problem.

JavaConcurrencyThread Safetyoptimistic lockCASpessimistic lockLocks
Java Tech Enthusiast
Written by

Java Tech Enthusiast

Sharing computer programming language knowledge, focusing on Java fundamentals, data structures, related tools, Spring Cloud, IntelliJ IDEA... Book giveaways, red‑packet rewards and other perks await!

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.