Backend Development 5 min read

Implementing Go's sync.Once Behavior in Java Using ReentrantLock

This article explains the Go sync.Once primitive, demonstrates its one‑time execution with concurrent goroutines, and shows how to recreate the same functionality in Java by using a static collection and ReentrantLock to ensure a block of code runs only once across multiple threads.

FunTester
FunTester
FunTester
Implementing Go's sync.Once Behavior in Java Using ReentrantLock

While studying Go, the author discovered the sync.Once object, which guarantees that a function is executed only once, even in concurrent scenarios.

The basic usage is demonstrated with a test function that launches ten goroutines, each calling once.Do to print a message; the console output shows the message appearing only once.

Such a one‑time execution pattern is commonly used during initialization of resources like Redis connection pools, where multiple asynchronous calls could otherwise cause race conditions.

In Java, similar needs are usually addressed with the lazy‑initialization singleton pattern, synchronized blocks, or java.util.concurrent.locks.ReentrantLock from the concurrent package.

The author provides a Java implementation that mimics sync.Once by using a static Vector<Integer> to store hash codes of executed closures and a static ReentrantLock to protect the critical section:

static Vector
ones = new Vector<>();
static ReentrantLock lock = new ReentrantLock();
/**
 * Thread‑safe single execution, modeled after Go's once method
 * @param v
 */
public static void once(Closure v) {
    try {
        lock.lock();
        int code = v.hashCode();
        if (!ones.contains(code)) {
            ones.add(code);
            v.call();
        }
    } catch (Exception e) {
        logger.warn("once execution failed", e);
    } finally {
        lock.unlock();
    }
}

A test class creates a closure that prints "FunTester" and invokes the once method ten times using Groovy's fun syntax. The console output confirms that, despite ten asynchronous calls, the closure runs only once.

package com.okcoin.hickwall.presses;
import com.okcoin.hickwall.presses.funtester.httpclient.FunHttp;
class OnceTest extends FunHttp {
    public static void main(String[] args) {
        def test = {
            output("FunTester");
        };
        10.times {
            fun {
                once(test);
            };
        }
    }
}
16:56:22 main 守护线程:Deamon开启!
16:56:22 F-1  FunTester
16:56:23 Deamon 异步线程池等待执行1次耗时:6 ms
16:56:23 Deamon 异步线程池关闭!

The result demonstrates that the Java version successfully reproduces the one‑time execution guarantee of Go's sync.Once .

JavaConcurrencyGosingletonReentrantLocksync.Once
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

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.