How to Guarantee a Single Instance of Spring Boot 3 on One Server
This article explains why running only one Spring Boot instance per server is essential for stability and data integrity, and presents four practical techniques—file locks, FileChannel locks, port binding, and IPC sockets—complete with code samples to prevent duplicate startups.
In production environments, ensuring that a Spring Boot application runs as a single instance on a server is crucial for system stability, resource efficiency, and data consistency.
Multiple instances can cause port conflicts, increased CPU and memory usage, duplicate scheduled tasks, and cache inconsistencies, leading to service crashes and data errors.
Four methods to enforce a single instance
1. File lock (simple)
The application creates a temporary lock file at startup; if the file already exists, the program exits, indicating another instance is running.
@SpringBootApplication
public class App {
private static final String LOCK_FILE = "app.lock";
public static void main(String[] args) {
File lockFile = new File(LOCK_FILE);
try {
// 1. Check if file exists
if (lockFile.exists()) {
System.out.println("Application is already running, do not start again...");
System.exit(1);
}
// 2. Create file
if (!lockFile.createNewFile()) {
throw new RuntimeException("Failed to create lock file");
}
System.err.printf("Lock file located: %s%n", lockFile.getAbsolutePath());
// 3. Add shutdown hook to delete lock file
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
if (lockFile.delete()) {
System.out.println("Lock file deleted.");
}
}));
} catch (Exception e) {
System.err.printf("Startup failed: %s%n", e.getMessage());
System.exit(1);
}
SpringApplication.run(App.class, args);
}
}When the application is started a second time, it prints:
Application is already running, do not start again...Note: the application must be stopped gracefully; otherwise the lock file remains and prevents future starts.
2. File lock (using FileChannel and FileLock)
This approach acquires an OS‑level file lock, which avoids the race condition of merely checking file existence.
try {
// 1. Create lock file
Path lockPath = new File("app.lock").toPath();
FileChannel channel = FileChannel.open(lockPath, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
// 2. Try to acquire lock
FileLock lock = channel.tryLock();
if (lock == null) {
System.err.println("Application is already running, do not start again...");
System.exit(1);
}
// 3. Add shutdown hook to release lock and delete file
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
if (lock != null) {
lock.release();
}
if (channel != null) {
channel.close();
}
new File("app.lock").delete();
} catch (Exception ignored) {}
}));
// 4. Normal startup
SpringApplication.run(App.class, args);
} catch (IOException e) {
System.err.printf("Startup failed: %s%n", e.getMessage());
System.exit(1);
}3. Network port binding
Attempt to bind a specific port; if binding fails, another instance is already using it.
try (ServerSocket socket = new ServerSocket(PORT)) {
System.out.println("Service can start normally...");
} catch (IOException e) {
System.err.println("Application is already running, do not start again...");
System.exit(1);
}
SpringApplication.run(SpringBootSingleInstanceApplication.class, args);This method is simple but cannot distinguish between a Spring Boot instance and another unrelated service occupying the same port.
4. Inter‑process communication (IPC) socket
Bind a loopback socket; if the bind succeeds, no other instance is running. The socket can also be used to query the service status.
try {
ServerSocket ipcSocket = new ServerSocket(IPC_PORT, 1, InetAddress.getLoopbackAddress());
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try { ipcSocket.close(); } catch (Exception ignored) {}
}));
// IPC listener thread
new Thread(() -> {
while (true) {
try (Socket client = ipcSocket.accept()) {
client.getOutputStream().write("ALIVE".getBytes(StandardCharsets.UTF_8));
} catch (Exception ignored) {}
}
}).start();
SpringApplication.run(SpringBootSingleInstanceApplication.class, args);
} catch (Exception e) {
System.err.println("IPC channel is already in use");
System.exit(1);
}Using IPC avoids false positives caused by other services occupying the same port and allows precise process‑level control.
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.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
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.
