java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java生成永不重复数字

使用Java生成永不重复的数字的实现方案

作者:喵手

在现代应用开发中,一个常见的需求是生成 永不重复的数字,无论是在订单系统中生成唯一订单号,还是分布式系统中生成唯一标识,生成不重复的数字或ID都是至关重要的,本期我们将关注 Java 生产永不重复的数字,通过多个角度剖析不同场景下的解决方案,需要的朋友可以参考下

摘要

本文以 Java 实现生成永不重复的数字 为核心,详细介绍了几种不同的实现方法,包括简单的自增算法、基于时间戳的生成方式、UUID 的使用,以及在分布式系统中常见的雪花算法。每种方法都有其适用的场景和优势。通过源码解析、实际使用案例分享和测试用例,我们将探讨如何在不同场景下生成唯一且不重复的数字或标识符,并分析各方法的优缺点,帮助开发者选择适合自己业务的最佳方案。

概述

在现代应用中,生成唯一且不重复的数字是一项关键任务,尤其是在分布式系统和多线程环境中。例如:

常见的生成方式

每种方式都有不同的使用场景,我们将逐一分析。

源码解析

1. 自增数字生成器

最简单的方式是使用自增数字,通过维护一个全局变量,每次生成一个数字时,将其自增。对于单线程环境或简单的需求场景,这种方式非常有效。

public class IncrementalNumberGenerator {
    private static long currentNumber = 0;

    // 线程安全的自增方法
    public static synchronized long getNextNumber() {
        return ++currentNumber;
    }
}

代码解析:

2. 时间戳结合随机数生成

时间戳(毫秒级)结合随机数生成唯一数字的方式较为常见,能够在较大范围内保证唯一性。

import java.util.Random;

public class TimestampRandomNumberGenerator {
    private static final Random random = new Random();

    public static String generateUniqueNumber() {
        long timestamp = System.currentTimeMillis();
        int randomNumber = random.nextInt(1000); // 随机生成0-999的数字
        return timestamp + String.format("%03d", randomNumber); // 拼接时间戳和随机数
    }
}

代码解析:

3. UUID 生成

import java.util.UUID;

public class UUIDGenerator {
    public static String generateUUID() {
        return UUID.randomUUID().toString();
    }
}

代码解析:

4. 雪花算法(Snowflake)

雪花算法是一种分布式环境下生成唯一ID的算法,由 Twitter 提出,它能够在分布式系统中生成64位的全局唯一ID。其ID由时间戳、机器ID和序列号组成,能保证在高并发情况下生成不重复的数字。

public class SnowflakeIdGenerator {
    private final long twepoch = 1288834974657L;
    private final long workerIdBits = 5L;
    private final long datacenterIdBits = 5L;
    private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
    private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
    private final long sequenceBits = 12L;
    private final long workerIdShift = sequenceBits;
    private final long datacenterIdShift = sequenceBits + workerIdBits;
    private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
    private final long sequenceMask = -1L ^ (-1L << sequenceBits);

    private long workerId;
    private long datacenterId;
    private long sequence = 0L;
    private long lastTimestamp = -1L;

    public SnowflakeIdGenerator(long workerId, long datacenterId) {
        if (workerId > maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException(String.format("Worker ID can't be greater than %d or less than 0", maxWorkerId));
        }
        if (datacenterId > maxDatacenterId || datacenterId < 0) {
            throw new IllegalArgumentException(String.format("Datacenter ID can't be greater than %d or less than 0", maxDatacenterId));
        }
        this.workerId = workerId;
        this.datacenterId = datacenterId;
    }

    public synchronized long nextId() {
        long timestamp = timeGen();

        if (timestamp < lastTimestamp) {
            throw new RuntimeException("Clock moved backwards. Refusing to generate ID");
        }

        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }

        lastTimestamp = timestamp;

        return ((timestamp - twepoch) << timestampLeftShift) |
               (datacenterId << datacenterIdShift) |
               (workerId << workerIdShift) |
               sequence;
    }

    private long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    private long timeGen() {
        return System.currentTimeMillis();
    }
}

代码解析:

雪花算法生成的ID是一个64位长的整数,能够在分布式环境下保证唯一性,且生成速度非常快。

使用案例分享

案例 1:基于自增数字生成订单号

对于中小型电商平台,生成唯一订单号的方式可以通过自增数字结合业务标识来完成。如下所示:

public class OrderService {
    private static long orderId = 0;

    public synchronized static String generateOrderNumber() {
        return "ORDER" + (++orderId);
    }
}

案例 2:分布式系统中的唯一标识生成

对于分布式系统,雪花算法是一种常见的解决方案。下面是一个分布式用户ID生成的示例:

public class UserIdGenerator {
    private static final SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1, 1); // 假设机器ID和数据中心ID为1

    public static long generateUserId() {
        return idGenerator.nextId();
    }
}

应用场景案例

一致性的关键。

优缺点分析

自增数字

时间戳结合随机数

UUID

雪花算法

核心类方法介绍

ystem.currentTimeMillis()

返回当前时间的毫秒数,自1970年1月1日开始计算。

Random.nextInt(int bound)

生成一个在 [0, bound) 范围内的随机整数。

UUID.randomUUID()

生成一个128位的随机UUID。

SnowflakeIdGenerator.nextId()

生成一个唯一的64位ID,用于分布式环境下的唯一标识生成。

测试用例

用例1:测试自增数字生成

@Test
public void testIncrementalNumberGeneration() {
    long num1 = IncrementalNumberGenerator.getNextNumber();
    long num2 = IncrementalNumberGenerator.getNextNumber();
    assertNotEquals(num1, num2);
}

代码解析:

如下是具体的代码解析,希望对大家有所帮助:

这段Java代码定义了一个测试方法 testIncrementalNumberGeneration,用于测试增量数字生成器是否能够生成不同的连续数字。

下面是这段代码的详细解读:

总结:这个测试用例的目的是验证增量数字生成器生成的两个连续数字是否不相同。增量数字生成器通常用于确保每个生成的数字都是唯一的,并且每个后续数字都比前一个大,这在生成序列号、版本号等时非常有用。

注意:代码中假设 IncrementalNumberGenerator 类已经定义,并且它的 getNextNumber 方法能够生成连续的数字。此外,测试方法的名称表明它专注于数字生成器的功能,确保每次调用 getNextNumber 方法都能得到一个更大的数字。如果 IncrementalNumberGenerator 是多线程安全的,那么即使在并发环境下,这个测试也应该能够通过。

用例2:测试雪花算法生成唯一ID

@Test
public void testSnowflakeIdGeneration() {
    SnowflakeIdGenerator generator = new SnowflakeIdGenerator(1, 1);
    long id1 = generator.nextId();
    long id2 = generator.nextId();
    assertNotEquals(id1, id2);
}

代码解析:

如下是具体的代码解析,希望对大家有所帮助:

这段Java代码定义了一个测试方法 testSnowflakeIdGeneration,用于测试雪花算法(Snowflake Algorithm)ID生成器是否能够生成不同的ID。

下面是这段代码的详细解读:

总结:这个测试用例的目的是验证ID生成器生成的两个连续ID是否不相同。雪花算法ID生成器通常用于分布式系统中生成唯一的ID,它结合了时间戳、数据中心ID和机器ID来确保生成的ID的唯一性。

小结

本文通过多种方案介绍了如何在 Java 中生成永不重复的数字。从简单的自增数字到适用于分布式环境的雪花算法,各种方案适用于不同的场景。对于单机环境,简单的自增数字或时间戳结合随机数足够使用,而在分布式环境下,雪花算法则成为了最佳选择。

总结

Java 生成不重复数字的方案多种多样,开发者需要根据具体的应用场景选择最合适的方案。本文从单机环境到分布式系统,依次分析了自增、时间戳结合随机数、UUID和雪花算法,并提供了相关代码和案例。掌握这些方案,可以帮助开发者在实际项目中应对不同的唯一标识生成需求,保证系统的稳定性和数据的一致性。

以上就是使用Java生成永不重复的数字的实现方案的详细内容,更多关于Java生成永不重复数字的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文