Which GUID Strategy Is Best for High‑Performance Java Services?

Generating globally unique identifiers (GUIDs) is essential for performance testing and business scenarios such as user behavior tracking, and this article compares five approaches—UUID, centralized services, Snowflake, ThreadLocal, and Atomic classes—detailing their principles, advantages, drawbacks, and suitable use cases for high‑concurrency systems.

FunTester
FunTester
FunTester
Which GUID Strategy Is Best for High‑Performance Java Services?

Generating globally unique identifiers (GUIDs) is a common requirement in performance testing and business scenarios. In the Supermarket 8 tracking system, unique IDs are used for database indexing, request tracing, and log analysis, e.g., for user actions like browsing or payment.

11.1 Unique Identifier Solutions

Below are five common GUID generation schemes and their characteristics.

UUID (java.util.UUID)

Principle : Generates a 128‑bit random identifier formatted as a 36‑character string, e.g., 3b9f3ef9-3c5b-449e-be3a-204c58252e1d.

Advantages

Global uniqueness : Extremely low collision probability.

High performance : Fast generation without network calls.

Stateless : No central coordination required.

Disadvantages

Length : 36 characters consume more storage.

Readability : No business meaning.

Non‑sequential : Unsuitable where ordered IDs are needed.

Use case : Suitable for logging and request tracing in the tracking system, but not ideal as a database primary key.

Example :

UUID uuid = UUID.randomUUID();
System.out.println(uuid); // 3b9f3ef9-3c5b-449e-be3a-204c58252e1d

Centralized Service

Principle : Use a central component such as Redis, MySQL, or ZooKeeper to generate incremental IDs, e.g., Redis INCR command.

Advantages

Uniqueness : Central management guarantees global uniqueness.

Traceability : Can integrate with distributed logging for request chain analysis.

Disadvantages

Performance bottleneck : Network latency and load on the central service.

Single‑point risk : Service outage blocks ID generation.

Use case : Combine data‑center ID and local sequence with Redis for distributed unique IDs, but network delay must be optimized.

Snowflake Algorithm

Principle : Generates a 64‑bit ID composed of timestamp, machine (or data‑center + worker) ID, and sequence, ensuring uniqueness and monotonicity.

Advantages

High performance : Local generation without network overhead.

Ordered : Timestamp and sequence provide roughly increasing IDs.

Scalable : Supports distributed deployment via machine IDs.

Disadvantages

Complex implementation : Requires custom code and handling of clock rollback.

Clock dependency : Time synchronization issues may cause collisions.

Use case : Ideal for order‑system primary keys in a high‑concurrency, distributed environment.

Implementation :

public class SnowflakeWorker {
    private static final long START_TIMESTAMP = 1712972492276L;
    private long dataId, workerId, sequence = 0L;
    // fields and constants omitted for brevity
    public synchronized long nextId() {
        long timestamp = System.currentTimeMillis();
        if (timestamp < lastTimestamp) {
            throw new RuntimeException("Clock moved backwards");
        }
        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & SEQUENCE_MASK;
            if (sequence == 0) {
                timestamp = nextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }
        lastTimestamp = timestamp;
        long id = ((timestamp - START_TIMESTAMP) << TIMESTAMP_LEFT_SHIFT)
                | (dataId << DATA_CENTER_ID_SHIFT)
                | (workerId << WORKER_ID_SHIFT) | sequence;
        return id & Long.MAX_VALUE;
    }
    // nextMillis method omitted
}

Example :

SnowflakeWorker snowflakeWorker = new SnowflakeWorker(1, 1);
for (int i = 0; i < 5; i++) {
    System.out.println(snowflakeWorker.nextId());
}

ThreadLocal

Principle : Each thread holds an independent counter via ThreadLocal, combining thread name and sequence, e.g., ThreadName-Sequence.

Advantages

High performance : Local counter, no lock overhead.

Simplicity : Easy to use with ThreadLocal.

Debuggable : ID contains thread information.

Disadvantages

Non‑global ordering : IDs are not sequential across threads.

Limited range : Integer counter may overflow (replaceable by Long).

Use case : Suitable for single‑machine load‑testing where IDs are needed for log tracing but not for distributed uniqueness.

Example :

ThreadLocal<Long> exclusive = ThreadLocal.withInitial(() -> 0L);
for (int i = 0; i < 4; i++) {
    Thread thread = new Thread(() -> {
        for (int j = 0; j < 10; j++) {
            Long id = exclusive.get();
            exclusive.set(id + 1);
            System.out.println(Thread.currentThread().getName() + "-" + (100000000 + id));
        }
    });
    thread.setName("Thread-" + i);
    thread.start();
}

AtomicInteger

Principle : Use java.util.concurrent.atomic.AtomicInteger with getAndIncrement to produce thread‑safe incremental IDs.

Advantages

High performance : CAS‑based, lock‑free.

Simplicity : No explicit thread management.

Monotonic : Globally increasing IDs, good for single‑node scenarios.

Disadvantages

Not distributed : Cannot be shared across multiple nodes.

Overflow risk : May need AtomicLong for larger ranges.

Use case : Ideal for high‑concurrency, single‑machine tracking ID generation.

Example :

AtomicInteger count = new AtomicInteger();
for (int i = 0; i < 4; i++) {
    new Thread(() -> {
        for (int j = 0; j < 10; j++) {
            System.out.println(count.getAndIncrement() + 10000000);
        }
    }).start();
}

11.4.2 Performance Analysis and Selection

In the tracking system, GUID generation must balance performance, uniqueness, and scenario suitability:

Single‑node : AtomicInteger offers the highest throughput for local log processing.

Distributed : Snowflake provides both performance and ordered IDs, making it appropriate for order‑system primary keys.

Log tracing : UUID or ThreadLocal generate readable IDs for debugging, suitable when performance is not critical.

Avoid centralized services : Due to network latency, Redis‑based IDs are not recommended unless node‑ID optimization is applied.

11.4.3 Optimization Recommendations

Single‑machine optimization : Use AtomicInteger or ThreadLocal together with object pools (e.g., FunObjPool) to reuse UserBehavior instances and reduce memory allocation.

Distributed optimization : Deploy Snowflake with configured data‑center and worker IDs, and regularly verify clock synchronization.

Monitoring and regression : After code changes, benchmark ID generation to ensure no new bottlenecks appear.

Length control : Adjust the format of IDs generated by ThreadLocal or AtomicInteger to meet storage constraints.

JavaPerformanceSnowflakeGUIDuniqueId
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

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.