Mimicking Go’s ‘go’ Keyword in Java and Groovy with Thread Pools
This article explains how to achieve Go‑style asynchronous execution in Java and Groovy by leveraging closures, the java.util.function.Supplier interface, custom thread‑pool wrappers, and Phaser‑based synchronization, complete with practical code examples and a custom ThreadFactory implementation.
Idea
Java supports closures, so we can recreate the effect of Go's go keyword by building an anonymous java.lang.Runnable implementation and handing it to a thread or thread pool. Groovy, which is fully compatible with Java syntax, can use the same approach with its groovy.lang.Closure type.
Java Implementation
Using java.util.function.Supplier (which has no parameters and returns a value) we wrap the asynchronous block and start a new thread:
package com.funtest.javatest;
import com.funtester.frame.SourceCode;
import java.util.function.Supplier;
public class Sync extends SourceCode {
public static void main(String[] args) {
sync(() -> {
sleep(0.1);
output("tester");
return DEFAULT_CHARSET;
});
output("FunTester");
}
public static void sync(Supplier f) {
new Thread(() -> {
f.get();
}).start();
}
}Console output demonstrates that the asynchronous block runs in a separate thread.
Groovy Implementation
Groovy simplifies the syntax further by using a Closure directly:
import com.funtester.frame.SourceCode
class Sync extends SourceCode {
public static void main(String[] args) {
sync {
sleep(0.2)
output(320)
}
output("FunTester")
}
static void sync(Closure f) {
new Thread(f()).start()
}
}The output is similar to the Java version, confirming that Groovy can achieve the same lightweight async behavior.
Thread‑Pool Upgrade
To avoid creating too many raw threads, the closure is wrapped into a Runnable and submitted to a thread‑pool utility:
/**
* Execute a code block asynchronously.
* Java requires a return value; Groovy does not.
*/
public static void fun(Supplier f) {
Runnable runnable = new Runnable() {
@Override
public void run() {
f.get();
}
};
ThreadPoolUtil.executeSync(runnable);
}A custom ThreadFactory is provided to give threads meaningful names:
/**
* Create a custom ThreadFactory that names threads "FT-XX".
*/
static ThreadFactory getFactory() {
if (FunFactory == null) {
synchronized (ThreadPoolUtil.class) {
if (FunFactory == null) {
FunFactory = new ThreadFactory() {
@Override
Thread newThread(Runnable runnable) {
Thread thread = new Thread(runnable);
int increment = threadNum.getAndIncrement();
String name = increment < 10 ? "00" + increment :
increment < 100 ? "0" + increment :
"" + increment;
thread.setName("FT-" + name);
return thread;
}
};
}
}
}
return FunFactory;
}Multi‑Thread Synchronization
When tasks need to be coordinated, java.util.concurrent.Phaser is used. The wrapper registers the current thread, runs the supplied block, and deregisters on completion:
/**
* Execute a code block asynchronously and synchronize with a Phaser.
*/
public static void fun(Supplier f, Phaser phaser) {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
phaser.register();
f.get();
} catch (Exception e) {
logger.warn("Error executing async method!", e);
} finally {
phaser.arriveAndDeregister();
}
}
};
ThreadPoolUtil.executeSync(runnable);
}IDE Support
IntelliJ IDEA’s Live Templates can generate the boilerplate for the custom thread factory and other snippets, making the code concise and repeatable.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
