Skip to content

DanielLiu1123/single-flight

Repository files navigation

Single Flight

Maven Central License: MIT Java Version

Single Flight is used to prevent the duplicate execution of expensive operations in concurrent environments.

Overview

The Single Flight pattern is a concurrency control mechanism that ensures expensive operations (such as database queries, API calls, or complex computations) are executed only once per key when multiple threads request the same resource concurrently.

Without Single Flight:
┌──────────────────────────────────────────────────────────────┐
│ Thread-1 (key:"user_123") ──► DB Query-1 ──► Result-1        │
│ Thread-2 (key:"user_123") ──► DB Query-2 ──► Result-2        │
│ Thread-3 (key:"user_123") ──► DB Query-3 ──► Result-3        │
│ Thread-4 (key:"user_123") ──► DB Query-4 ──► Result-4        │
└──────────────────────────────────────────────────────────────┘
Result: 4 separate database calls for the same key
        (All results are identical but computed 4 times)

With Single Flight:
┌──────────────────────────────────────────────────────────────┐
│ Thread-1 (key:"user_123") ──► DB Query-1 ──► Result-1        │
│ Thread-2 (key:"user_123") ──► Wait       ──► Result-1        │
│ Thread-3 (key:"user_123") ──► Wait       ──► Result-1        │
│ Thread-4 (key:"user_123") ──► Wait       ──► Result-1        │
└──────────────────────────────────────────────────────────────┘
Result: 1 database call, all threads share the same result

Getting Started

Installation

Maven:

<dependency>
    <groupId>io.github.danielliu1123</groupId>
    <artifactId>single-flight</artifactId>
    <version>latest</version>
</dependency>

Gradle:

implementation "io.github.danielliu1123:single-flight:<latest>"

Used as source:

mkdir -p singleflight && curl -L -o singleflight/SingleFlight.java https://raw.githubusercontent.com/DanielLiu1123/single-flight/refs/heads/main/single-flight/src/main/java/singleflight/SingleFlight.java

Usage

// 1. Using the global instance
User user = SingleFlight.runDefault("user:123", () -> {
    return userService.loadUser("123");
});

// 2. Using a dedicated instance

// 2-1. Using default options
SingleFlight<String, User> userSingleFlight = new SingleFlight<>();

// 2-2. Using custom options
SingleFlight<String, User> userSingleFlight = new SingleFlight<>(
    SingleFlight.Options.builder()
        .cacheException(true)
        .build()
);

User user = userSingleFlight.run("123", () -> {
    return userService.loadUser("123");
});

Use Cases

Recommended Scenarios

Single Flight is particularly effective in the following scenarios:

  • Database queries with high cache miss rates
  • External API calls that are expensive or rate-limited
  • Complex computations that are CPU-intensive
  • Cache warming operations to prevent cache stampedes

Not Recommended For

Single Flight should be avoided in these situations:

  • Operations that must always execute independently (e.g., logging, metrics collection)
  • Very fast operations where coordination overhead exceeds the benefits
  • Operations with side effects that need to occur for each individual call

License

The MIT License.

About

SingleFlight for Java — Collapse concurrent duplicate calls into one.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published