使用Java生成永不重復(fù)的數(shù)字的實(shí)現(xiàn)方案
摘要
本文以 Java 實(shí)現(xiàn)生成永不重復(fù)的數(shù)字 為核心,詳細(xì)介紹了幾種不同的實(shí)現(xiàn)方法,包括簡(jiǎn)單的自增算法、基于時(shí)間戳的生成方式、UUID 的使用,以及在分布式系統(tǒng)中常見(jiàn)的雪花算法。每種方法都有其適用的場(chǎng)景和優(yōu)勢(shì)。通過(guò)源碼解析、實(shí)際使用案例分享和測(cè)試用例,我們將探討如何在不同場(chǎng)景下生成唯一且不重復(fù)的數(shù)字或標(biāo)識(shí)符,并分析各方法的優(yōu)缺點(diǎn),幫助開(kāi)發(fā)者選擇適合自己業(yè)務(wù)的最佳方案。
概述
在現(xiàn)代應(yīng)用中,生成唯一且不重復(fù)的數(shù)字是一項(xiàng)關(guān)鍵任務(wù),尤其是在分布式系統(tǒng)和多線程環(huán)境中。例如:
- 電商系統(tǒng)中生成唯一訂單號(hào)
- 社交網(wǎng)絡(luò)中為用戶生成唯一的ID
- 分布式數(shù)據(jù)庫(kù)中生成唯一的主鍵
常見(jiàn)的生成方式
- 自增數(shù)字:最簡(jiǎn)單的生成唯一數(shù)字的方式,即通過(guò)一個(gè)全局遞增的數(shù)字生成器。
- 時(shí)間戳結(jié)合隨機(jī)數(shù):通過(guò)系統(tǒng)當(dāng)前時(shí)間(時(shí)間戳)加上隨機(jī)數(shù)來(lái)生成不重復(fù)的數(shù)字。
- UUID:Java 自帶的 UUID 類,能夠生成幾乎保證全局唯一的標(biāo)識(shí)符。
- 雪花算法(Snowflake):Twitter 提出的分布式系統(tǒng)中生成全局唯一ID的算法。
每種方式都有不同的使用場(chǎng)景,我們將逐一分析。
源碼解析
1. 自增數(shù)字生成器
最簡(jiǎn)單的方式是使用自增數(shù)字,通過(guò)維護(hù)一個(gè)全局變量,每次生成一個(gè)數(shù)字時(shí),將其自增。對(duì)于單線程環(huán)境或簡(jiǎn)單的需求場(chǎng)景,這種方式非常有效。
public class IncrementalNumberGenerator {
private static long currentNumber = 0;
// 線程安全的自增方法
public static synchronized long getNextNumber() {
return ++currentNumber;
}
}
代碼解析:
currentNumber作為靜態(tài)變量,存儲(chǔ)當(dāng)前的數(shù)字。getNextNumber方法使用synchronized關(guān)鍵字確保線程安全,在并發(fā)環(huán)境下防止多線程同時(shí)修改currentNumber的問(wèn)題。
2. 時(shí)間戳結(jié)合隨機(jī)數(shù)生成
時(shí)間戳(毫秒級(jí))結(jié)合隨機(jī)數(shù)生成唯一數(shù)字的方式較為常見(jiàn),能夠在較大范圍內(nèi)保證唯一性。
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); // 隨機(jī)生成0-999的數(shù)字
return timestamp + String.format("%03d", randomNumber); // 拼接時(shí)間戳和隨機(jī)數(shù)
}
}
代碼解析:
System.currentTimeMillis()獲取當(dāng)前時(shí)間戳(單位:毫秒)。- 使用
Random類生成一個(gè)三位隨機(jī)數(shù)。 - 將時(shí)間戳和隨機(jī)數(shù)拼接成一個(gè)字符串,保證唯一性。
3. UUID 生成
import java.util.UUID;
public class UUIDGenerator {
public static String generateUUID() {
return UUID.randomUUID().toString();
}
}
代碼解析:
UUID.randomUUID()生成一個(gè)隨機(jī)的 UUID。- UUID 通常由32個(gè)字符組成,包含字母和數(shù)字,格式如
550e8400-e29b-41d4-a716-446655440000。
4. 雪花算法(Snowflake)
雪花算法是一種分布式環(huán)境下生成唯一ID的算法,由 Twitter 提出,它能夠在分布式系統(tǒng)中生成64位的全局唯一ID。其ID由時(shí)間戳、機(jī)器ID和序列號(hào)組成,能保證在高并發(fā)情況下生成不重復(fù)的數(shù)字。
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();
}
}
代碼解析:
- 時(shí)間戳:用于確保生成的ID按照時(shí)間順序遞增。
- 機(jī)器ID和數(shù)據(jù)中心ID:用于在分布式系統(tǒng)中標(biāo)識(shí)不同的機(jī)器和數(shù)據(jù)中心,防止ID沖突。
- 序列號(hào):在同一毫秒內(nèi)生成多個(gè)ID時(shí),用于區(qū)分這些ID。
雪花算法生成的ID是一個(gè)64位長(zhǎng)的整數(shù),能夠在分布式環(huán)境下保證唯一性,且生成速度非??臁?/p>
使用案例分享
案例 1:基于自增數(shù)字生成訂單號(hào)
對(duì)于中小型電商平臺(tái),生成唯一訂單號(hào)的方式可以通過(guò)自增數(shù)字結(jié)合業(yè)務(wù)標(biāo)識(shí)來(lái)完成。如下所示:
public class OrderService {
private static long orderId = 0;
public synchronized static String generateOrderNumber() {
return "ORDER" + (++orderId);
}
}
案例 2:分布式系統(tǒng)中的唯一標(biāo)識(shí)生成
對(duì)于分布式系統(tǒng),雪花算法是一種常見(jiàn)的解決方案。下面是一個(gè)分布式用戶ID生成的示例:
public class UserIdGenerator {
private static final SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1, 1); // 假設(shè)機(jī)器ID和數(shù)據(jù)中心ID為1
public static long generateUserId() {
return idGenerator.nextId();
}
}
應(yīng)用場(chǎng)景案例
- 訂單號(hào)生成:在電商系統(tǒng)中,需要為每個(gè)訂單生成唯一的訂單號(hào),避免重復(fù)的訂單處理和數(shù)據(jù)混亂。
- 分布式系統(tǒng)中的唯一標(biāo)識(shí)生成:在分布式架構(gòu)中,多個(gè)節(jié)點(diǎn)同時(shí)進(jìn)行任務(wù)時(shí),生成全局唯一的ID是保障數(shù)據(jù)
一致性的關(guān)鍵。
優(yōu)缺點(diǎn)分析
自增數(shù)字
- 優(yōu)點(diǎn):實(shí)現(xiàn)簡(jiǎn)單,易于管理。
- 缺點(diǎn):僅適用于單機(jī)環(huán)境,多線程環(huán)境下需要同步處理,且不適合分布式系統(tǒng)。
時(shí)間戳結(jié)合隨機(jī)數(shù)
- 優(yōu)點(diǎn):能夠在大多數(shù)場(chǎng)景下保證唯一性,生成速度較快。
- 缺點(diǎn):在高并發(fā)環(huán)境下有可能出現(xiàn)重復(fù),隨機(jī)數(shù)的范圍較小。
UUID
- 優(yōu)點(diǎn):能夠生成幾乎全局唯一的標(biāo)識(shí),且使用簡(jiǎn)單。
- 缺點(diǎn):UUID較長(zhǎng),不適合需要短ID的場(chǎng)景。
雪花算法
- 優(yōu)點(diǎn):適合分布式環(huán)境,能夠保證生成ID的唯一性和有序性。
- 缺點(diǎn):實(shí)現(xiàn)較為復(fù)雜,需要合理配置機(jī)器ID和數(shù)據(jù)中心ID。
核心類方法介紹
ystem.currentTimeMillis()
返回當(dāng)前時(shí)間的毫秒數(shù),自1970年1月1日開(kāi)始計(jì)算。
Random.nextInt(int bound)
生成一個(gè)在 [0, bound) 范圍內(nèi)的隨機(jī)整數(shù)。
UUID.randomUUID()
生成一個(gè)128位的隨機(jī)UUID。
SnowflakeIdGenerator.nextId()
生成一個(gè)唯一的64位ID,用于分布式環(huán)境下的唯一標(biāo)識(shí)生成。
測(cè)試用例
用例1:測(cè)試自增數(shù)字生成
@Test
public void testIncrementalNumberGeneration() {
long num1 = IncrementalNumberGenerator.getNextNumber();
long num2 = IncrementalNumberGenerator.getNextNumber();
assertNotEquals(num1, num2);
}
代碼解析:
如下是具體的代碼解析,希望對(duì)大家有所幫助:
這段Java代碼定義了一個(gè)測(cè)試方法 testIncrementalNumberGeneration,用于測(cè)試增量數(shù)字生成器是否能夠生成不同的連續(xù)數(shù)字。
下面是這段代碼的詳細(xì)解讀:
@Test:這是一個(gè)JUnit注解,表示接下來(lái)的方法是測(cè)試方法。public void testIncrementalNumberGeneration() { ... }:定義了一個(gè)名為testIncrementalNumberGeneration的測(cè)試方法。long num1 = IncrementalNumberGenerator.getNextNumber();:調(diào)用IncrementalNumberGenerator類的靜態(tài)方法getNextNumber來(lái)生成第一個(gè)數(shù)字,并將其存儲(chǔ)在變量num1中。long num2 = IncrementalNumberGenerator.getNextNumber();:再次調(diào)用getNextNumber方法生成第二個(gè)數(shù)字,并將其存儲(chǔ)在變量num2中。assertNotEquals(num1, num2);:使用assertNotEquals斷言方法來(lái)驗(yàn)證num1和num2是否不同。如果兩個(gè)數(shù)字不相同,測(cè)試將通過(guò);如果相同,則測(cè)試將失敗。
總結(jié):這個(gè)測(cè)試用例的目的是驗(yàn)證增量數(shù)字生成器生成的兩個(gè)連續(xù)數(shù)字是否不相同。增量數(shù)字生成器通常用于確保每個(gè)生成的數(shù)字都是唯一的,并且每個(gè)后續(xù)數(shù)字都比前一個(gè)大,這在生成序列號(hào)、版本號(hào)等時(shí)非常有用。
注意:代碼中假設(shè) IncrementalNumberGenerator 類已經(jīng)定義,并且它的 getNextNumber 方法能夠生成連續(xù)的數(shù)字。此外,測(cè)試方法的名稱表明它專注于數(shù)字生成器的功能,確保每次調(diào)用 getNextNumber 方法都能得到一個(gè)更大的數(shù)字。如果 IncrementalNumberGenerator 是多線程安全的,那么即使在并發(fā)環(huán)境下,這個(gè)測(cè)試也應(yīng)該能夠通過(guò)。
用例2:測(cè)試雪花算法生成唯一ID
@Test
public void testSnowflakeIdGeneration() {
SnowflakeIdGenerator generator = new SnowflakeIdGenerator(1, 1);
long id1 = generator.nextId();
long id2 = generator.nextId();
assertNotEquals(id1, id2);
}
代碼解析:
如下是具體的代碼解析,希望對(duì)大家有所幫助:
這段Java代碼定義了一個(gè)測(cè)試方法 testSnowflakeIdGeneration,用于測(cè)試雪花算法(Snowflake Algorithm)ID生成器是否能夠生成不同的ID。
下面是這段代碼的詳細(xì)解讀:
@Test:這是一個(gè)JUnit注解,表示接下來(lái)的方法是測(cè)試方法。public void testSnowflakeIdGeneration() { ... }:定義了一個(gè)名為testSnowflakeIdGeneration的測(cè)試方法。SnowflakeIdGenerator generator = new SnowflakeIdGenerator(1, 1);:創(chuàng)建了SnowflakeIdGenerator類的一個(gè)實(shí)例,這個(gè)類可能是一個(gè)實(shí)現(xiàn)了Twitter雪花算法的ID生成器。它的構(gòu)造函數(shù)接受兩個(gè)參數(shù),通常表示數(shù)據(jù)中心ID和機(jī)器ID。long id1 = generator.nextId();:調(diào)用generator實(shí)例的nextId方法生成第一個(gè)ID,并將其存儲(chǔ)在變量id1中。long id2 = generator.nextId();:再次調(diào)用nextId方法生成第二個(gè)ID,并將其存儲(chǔ)在變量id2中。assertNotEquals(id1, id2);:使用assertNotEquals斷言方法來(lái)驗(yàn)證id1和id2是否不同。如果兩個(gè)ID不相同,測(cè)試將通過(guò);如果相同,則測(cè)試將失敗。
總結(jié):這個(gè)測(cè)試用例的目的是驗(yàn)證ID生成器生成的兩個(gè)連續(xù)ID是否不相同。雪花算法ID生成器通常用于分布式系統(tǒng)中生成唯一的ID,它結(jié)合了時(shí)間戳、數(shù)據(jù)中心ID和機(jī)器ID來(lái)確保生成的ID的唯一性。
小結(jié)
本文通過(guò)多種方案介紹了如何在 Java 中生成永不重復(fù)的數(shù)字。從簡(jiǎn)單的自增數(shù)字到適用于分布式環(huán)境的雪花算法,各種方案適用于不同的場(chǎng)景。對(duì)于單機(jī)環(huán)境,簡(jiǎn)單的自增數(shù)字或時(shí)間戳結(jié)合隨機(jī)數(shù)足夠使用,而在分布式環(huán)境下,雪花算法則成為了最佳選擇。
總結(jié)
Java 生成不重復(fù)數(shù)字的方案多種多樣,開(kāi)發(fā)者需要根據(jù)具體的應(yīng)用場(chǎng)景選擇最合適的方案。本文從單機(jī)環(huán)境到分布式系統(tǒng),依次分析了自增、時(shí)間戳結(jié)合隨機(jī)數(shù)、UUID和雪花算法,并提供了相關(guān)代碼和案例。掌握這些方案,可以幫助開(kāi)發(fā)者在實(shí)際項(xiàng)目中應(yīng)對(duì)不同的唯一標(biāo)識(shí)生成需求,保證系統(tǒng)的穩(wěn)定性和數(shù)據(jù)的一致性。
以上就是使用Java生成永不重復(fù)的數(shù)字的實(shí)現(xiàn)方案的詳細(xì)內(nèi)容,更多關(guān)于Java生成永不重復(fù)數(shù)字的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
10個(gè)Elasticsearch查詢的實(shí)用技巧分享
Elasticsearch是一個(gè)非常流行的搜索引擎,已經(jīng)成為了許多企業(yè)的首選解決方案。本文將向大家介紹10個(gè)實(shí)用的Elasticsearch查詢技巧,并配上對(duì)應(yīng)的代碼示例,希望對(duì)大家有所幫助2023-04-04
Kotlin開(kāi)發(fā)Android應(yīng)用實(shí)例詳解
這篇文章主要介紹了Kotlin開(kāi)發(fā)Android應(yīng)用實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-05-05
feign參數(shù)過(guò)多導(dǎo)致調(diào)用失敗的解決方案
這篇文章主要介紹了feign參數(shù)過(guò)多導(dǎo)致調(diào)用失敗的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
Java aop面向切面編程(aspectJweaver)案例詳解
這篇文章主要介紹了Java aop面向切面編程(aspectJweaver)案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08
Spring Security自定義登錄原理及實(shí)現(xiàn)詳解
這篇文章主要介紹了Spring Security自定義登錄原理及實(shí)現(xiàn)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09
一文詳解SpringBoot響應(yīng)壓縮功能的配置與優(yōu)化
Spring Boot的響應(yīng)壓縮功能基于智能協(xié)商機(jī)制,需同時(shí)滿足很多條件,本文主要為大家詳細(xì)介紹了SpringBoot響應(yīng)壓縮功能的配置與優(yōu)化,需要的可以參考下2025-03-03
SpringMVC整合kinfe4j及問(wèn)題解決分析
這篇文章主要為大家介紹了SpringMVC整合kinfe4j及問(wèn)題解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
Java數(shù)據(jù)結(jié)構(gòu) 遞歸之迷宮回溯案例講解
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)遞歸之迷宮回溯案例講解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08

