Backend Development 8 min read

Understanding Spin Locks and Implementing a Reentrant Spin Lock in Java

This article explains the concept of spin locks, compares them with non‑spin locks, discusses their advantages and drawbacks, and provides Java code examples—including an AtomicLong implementation and a custom re‑entrant spin lock—to illustrate how spin locks work in concurrent programming.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Understanding Spin Locks and Implementing a Reentrant Spin Lock in Java

What Is a Spin

A "spin" can be understood as "self‑rotation", where the rotation refers to a loop such as a while or for loop. A spin lock repeatedly loops, trying to acquire the lock until it succeeds, instead of blocking like a traditional lock.

Spin vs. Non‑Spin Lock Acquisition Process

A spin lock does not relinquish the CPU time slice; it continuously attempts to acquire the lock, retrying immediately if it fails.

A non‑spin lock, when it cannot obtain the lock, puts the thread into a sleeping state, allowing the CPU to perform other work until the lock holder releases the lock, after which the sleeping thread is awakened and retries.

The biggest difference between a non‑spin lock and a spin lock is that the former blocks the thread until it is woken up, while the latter keeps trying without blocking.

Benefits of Spin Locks

Blocking and waking a thread incurs high overhead. If the synchronized code block is simple, the cost of a context switch may exceed the actual work.

When the critical section is short, keeping the thread in a runnable state and spinning to acquire the lock can avoid the overhead of thread state changes, improving efficiency.

Thus, a spin lock saves the cost of thread‑state switches by using a loop to keep trying to acquire the lock.

AtomicLong Implementation

In Java 1.5 and later, the java.util.concurrent package provides atomic classes that are essentially built on spin‑lock mechanisms.

Below is the getAndIncrement method of AtomicLong :

public final long getAndIncrement() {
    return unsafe.getAndAddLong(this, valueOffset, 1L);
}

The method calls unsafe.getAndAddLong , whose implementation uses a do‑while loop:

public final long getAndAddLong(Object var1, long var2, long var4) {
    long var6;
    do {
        var6 = this.getLongVolatile(var1, var2);
    } while (!this.compareAndSwapLong(var1, var2, var6, var6 + var4));
    return var6;
}

The do‑while loop is a classic spin operation: if another thread interferes, the loop repeats until the update succeeds.

Implementing a Re‑entrant Spin Lock Example

import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;

/**
 * Description: Implementation of a re‑entrant spin lock
 */
public class ReentrantSpinLock {
    private AtomicReference
owner = new AtomicReference<>();
    // Re‑entry count
    private int count = 0;

    public void lock() {
        Thread t = Thread.currentThread();
        if (t == owner.get()) {
            ++count;
            return;
        }
        // Spin to acquire lock
        while (!owner.compareAndSet(null, t)) {
            System.out.println("自旋了");
        }
    }

    public void unlock() {
        Thread t = Thread.currentThread();
        // Only the owning thread can unlock
        if (t == owner.get()) {
            if (count > 0) {
                --count;
            } else {
                // No CAS needed here because there is no contention
                owner.set(null);
            }
        }
    }

    public static void main(String[] args) {
        ReentrantSpinLock spinLock = new ReentrantSpinLock();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "开始尝试获取自旋锁");
                spinLock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + "获取到了自旋锁");
                    Thread.sleep(4000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    spinLock.unlock();
                    System.out.println(Thread.currentThread().getName() + "释放了了自旋锁");
                }
            }
        };
        Thread thread1 = new Thread(runnable);
        Thread thread2 = new Thread(runnable);
        thread1.start();
        thread2.start();
    }
}

Running the program produces output similar to:

...
自旋了
自旋了
自旋了
自旋了
自旋了
自旋了
自旋了
自旋了
Thread-0释放了了自旋锁
Thread-1获取到了自旋锁

The repeated "自旋了" lines show that the CPU continues to run while spinning.

Drawbacks of Spin Locks

Although spin locks avoid the overhead of thread switching, they introduce a different cost: continuous attempts to acquire the lock waste CPU cycles if the lock remains unavailable, eventually becoming more expensive than a blocking lock.

Applicable Scenarios

Spin locks are suitable when the concurrency level is moderate and the critical section is short, allowing the avoidance of thread‑switch overhead.

If the critical section is long and a thread holds the lock for an extended period, a spin lock is inappropriate because it would waste CPU cycles without making progress.

JavaconcurrencymultithreadingAtomicLongspin lockReentrant Lock
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

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.