Java中的雪花算法(Snowflake Algorithm)是一種用于生成唯一ID的算法,可以在分布式系統(tǒng)環(huán)境中防止ID重復(fù)。這種算法最初由Twitter開發(fā),用于生成Twitter的唯一ID,由于其簡(jiǎn)單易懂和高效,已成為目前最常用的生成唯一ID的算法之一。
雪花算法生成的ID是一個(gè)64位的長(zhǎng)整型數(shù)字,可以分為四個(gè)部分:
- 符號(hào)位(始終為0,占用1位)。
- 時(shí)間戳(毫秒級(jí),占用41位),可以用的年限約69年。
- 數(shù)據(jù)中心ID(可以定義具體數(shù)據(jù)中心ID的位數(shù),占用5位),用于區(qū)分不同的數(shù)據(jù)中心。
- 工作機(jī)器ID(可以定義具體工作機(jī)器ID的位數(shù),占用5位),用于區(qū)分不同的工作機(jī)器。
以下是Java實(shí)現(xiàn)的基本流程:
- 獲得時(shí)間戳,精確到毫秒級(jí)。
- 將所有位數(shù)的值全部初始化為0。
- 填充時(shí)間戳,對(duì)應(yīng)41位。
- 填充數(shù)據(jù)中心ID,根據(jù)自身需求設(shè)置位數(shù)。
- 填充工作機(jī)器ID,根據(jù)自身需求設(shè)置位數(shù)。
- 填充序列號(hào),一般使用一個(gè)計(jì)數(shù)器,生成一系列自增的整數(shù)。
- 將上述所有部分組合成一條64位的長(zhǎng)整型數(shù)字,即為唯一ID,生成完成。
以下是一個(gè)Java實(shí)現(xiàn)的示例代碼:
public class SnowFlake {
// 起始的時(shí)間戳
private final static long START_TIMESTAMP = 1480166465631L;
// 每一部分占用的位數(shù),符號(hào)位不算在內(nèi)
private final static long SEQUENCE_BIT = 12; // 序列號(hào)占用的位數(shù)
private final static long MACHINE_BIT = 5; // 機(jī)器標(biāo)識(shí)占用的位數(shù)
private final static long DATACENTER_BIT = 5; // 數(shù)據(jù)中心占用的位數(shù)
// 每一部分的最大值
private final static long MAX_SEQUENCE = ~(-1L << SEQUENCE_BIT);
private final static long MAX_MACHINE_NUM = ~(-1L << MACHINE_BIT);
private final static long MAX_DATACENTER_NUM = ~(-1L << DATACENTER_BIT);
// 每一部分向左的位移
private final static long MACHINE_LEFT = SEQUENCE_BIT;
private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
private final static long TIMESTAMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;
private long datacenterId; // 數(shù)據(jù)中心
private long machineId; // 機(jī)器標(biāo)識(shí)
private long sequence = 0L; // 序列號(hào)
private long lastTimestamp = -1L;// 上一次時(shí)間戳
public SnowFlake(long datacenterId, long machineId) {
if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
throw new IllegalArgumentException("Datacenter ID can't be greater than MAX_DATACENTER_NUM or less than 0");
}
if (machineId > MAX_MACHINE_NUM || machineId < 0) {
throw new IllegalArgumentException("Machine ID can't be greater than MAX_MACHINE_NUM or less than 0");
}
this.datacenterId = datacenterId;
this.machineId = machineId;
}
/**
* 產(chǎn)生下一個(gè)ID
*
* @return 下一個(gè)ID
*/
public synchronized long nextId() {
long currTimestamp = getTimestamp();
if (currTimestamp < lastTimestamp) {
throw new RuntimeException("Clock moved backwards. Refusing to generate id");
}
// 如果是同一時(shí)間生成的,則進(jìn)行毫秒內(nèi)序列
if (currTimestamp == lastTimestamp) {
sequence = (sequence + 1) & MAX_SEQUENCE;
// 序列號(hào)已經(jīng)達(dá)到最大值,下一個(gè)毫秒
if (sequence == 0L) {
currTimestamp = getNextTimestamp();
}
} else {
// 時(shí)間戳改變,毫秒內(nèi)序列重置
sequence = 0L;
}
// 上次生成ID的時(shí)間截
lastTimestamp = currTimestamp;
// 移位并通過或運(yùn)算拼到一起組成64位的ID
return (currTimestamp - START_TIMESTAMP) << TIMESTAMP_LEFT // 時(shí)間戳部分
| datacenterId << DATACENTER_LEFT // 數(shù)據(jù)中心部分
| machineId << MACHINE_LEFT // 機(jī)器標(biāo)識(shí)部分
| sequence; // 序列號(hào)部分
}
/**
* 獲取下一個(gè)毫秒數(shù)
*
* @return 下一個(gè)毫秒數(shù)
*/
private long getNextTimestamp() {
long timestamp = getTimestamp();
while (timestamp <= lastTimestamp) {
timestamp = getTimestamp();
}
return timestamp;
}
/**
* 獲取當(dāng)前的時(shí)間戳
*
* @return 當(dāng)前的時(shí)間戳
*/
private long getTimestamp() {
return System.currentTimeMillis();
}
public static void main(String[] args) {
SnowFlake snowFlake = new SnowFlake(1, 1);
long startTime = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
System.out.println(snowFlake.nextId());
}
long endTime = System.nanoTime();
System.out.println("用時(shí):" + (endTime - startTime) / 1000000 + "ms");
}
}
在以上示例代碼中,SnowFlake類的構(gòu)造函數(shù)接收數(shù)據(jù)中心ID和機(jī)器ID作為參數(shù),用戶可以根據(jù)自己的業(yè)務(wù)需求設(shè)置不同的數(shù)值。nextId()方法用于生成雪花算法的唯一ID。
除此之外,為了防止時(shí)間回退的情況,采用了getNextTimestamp()方法來獲得下一個(gè)合法的時(shí)間戳??梢钥吹剑@是一種高效、易擴(kuò)展、高可用的算法,適合于生成分布式系統(tǒng)下唯一的ID。文章來源:http://www.zghlxwxcb.cn/news/detail-426515.html
?文章來源地址http://www.zghlxwxcb.cn/news/detail-426515.html
到了這里,關(guān)于實(shí)現(xiàn)高性能ID生成器:詳解Java雪花算法的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!