Twitter的snowflake解決了能夠按照時(shí)間生成有序且不重復(fù)的全局唯一ID衣吠!
--- C# 版本源碼:
public class IdWorker
{
//機(jī)器ID
private static long workerId;
private static long twepoch = 687888001020L; //唯一時(shí)間,這是一個(gè)避免重復(fù)的隨機(jī)量壤靶,自行設(shè)定不要大于當(dāng)前時(shí)間戳
private static long sequence = 0L;
private static int workerIdBits = 4; //機(jī)器碼字節(jié)數(shù)缚俏。4個(gè)字節(jié)用來(lái)保存機(jī)器碼(定義為L(zhǎng)ong類(lèi)型會(huì)出現(xiàn),最大偏移64位贮乳,所以左移64位沒(méi)有意義)
public static long maxWorkerId = -1L ^ -1L << workerIdBits; //最大機(jī)器ID
private static int sequenceBits = 10; //計(jì)數(shù)器字節(jié)數(shù)忧换,10個(gè)字節(jié)用來(lái)保存計(jì)數(shù)碼
private static int workerIdShift = sequenceBits; //機(jī)器碼數(shù)據(jù)左移位數(shù),就是后面計(jì)數(shù)器占用的位數(shù)
private static int timestampLeftShift = sequenceBits + workerIdBits; //時(shí)間戳左移動(dòng)位數(shù)就是機(jī)器碼和計(jì)數(shù)器總字節(jié)數(shù)
public static long sequenceMask = -1L ^ -1L << sequenceBits; //一微秒內(nèi)可以產(chǎn)生計(jì)數(shù)向拆,如果達(dá)到該值則等到下一微妙在進(jìn)行生成
private long lastTimestamp = -1L;
/// <summary>
/// 機(jī)器碼
/// </summary>
/// <param name="workerId"></param>
public IdWorker(long workerId)
{
if (workerId > maxWorkerId || workerId < 0)
throw new Exception(string.Format("worker Id can't be greater than {0} or less than 0 ", workerId));
IdWorker.workerId = workerId;
}
public long nextId()
{
lock (this)
{
long timestamp = timeGen();
if (this.lastTimestamp == timestamp)
{ //同一微妙中生成ID
IdWorker.sequence = (IdWorker.sequence + 1) & IdWorker.sequenceMask; //用&運(yùn)算計(jì)算該微秒內(nèi)產(chǎn)生的計(jì)數(shù)是否已經(jīng)到達(dá)上限
if (IdWorker.sequence == 0)
{
//一微妙內(nèi)產(chǎn)生的ID計(jì)數(shù)已達(dá)上限亚茬,等待下一微妙
timestamp = tillNextMillis(this.lastTimestamp);
}
}
else
{ //不同微秒生成ID
IdWorker.sequence = 0; //計(jì)數(shù)清0
}
if (timestamp < lastTimestamp)
{ //如果當(dāng)前時(shí)間戳比上一次生成ID時(shí)時(shí)間戳還小,拋出異常浓恳,因?yàn)椴荒鼙WC現(xiàn)在生成的ID之前沒(méi)有生成過(guò)
throw new Exception(string.Format("Clock moved backwards. Refusing to generate id for {0} milliseconds",
this.lastTimestamp - timestamp));
}
this.lastTimestamp = timestamp; //把當(dāng)前時(shí)間戳保存為最后生成ID的時(shí)間戳
long nextId = (timestamp - twepoch << timestampLeftShift) | IdWorker.workerId << IdWorker.workerIdShift | IdWorker.sequence;
return nextId;
}
}
/// <summary>
/// 獲取下一微秒時(shí)間戳
/// </summary>
/// <param name="lastTimestamp"></param>
/// <returns></returns>
private long tillNextMillis(long lastTimestamp)
{
long timestamp = timeGen();
while (timestamp <= lastTimestamp)
{
timestamp = timeGen();
}
return timestamp;
}
/// <summary>
/// 生成當(dāng)前時(shí)間戳
/// </summary>
/// <returns></returns>
private long timeGen()
{
return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
}
}
C#調(diào)用方法:
IdWorker idworker = new IdWorker(1);
for (int i = 0; i < 1000; i++)
{
Response.Write(idworker.nextId() + "<br/>");
}
--- java 版本源碼:
public class IdWorker {
private final long workerId;
private final static long twepoch = 1288834974657L;
private long sequence = 0L;
private final static long workerIdBits = 4L;
public final static long maxWorkerId = -1L ^ -1L << workerIdBits;
private final static long sequenceBits = 10L;
private final static long workerIdShift = sequenceBits;
private final static long timestampLeftShift = sequenceBits + workerIdBits;
public final static long sequenceMask = -1L ^ -1L << sequenceBits;
private long lastTimestamp = -1L;
public IdWorker(final long workerId) {
super();
if (workerId > this.maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format(
"worker Id can't be greater than %d or less than 0",
this.maxWorkerId));
}
this.workerId = workerId;
}
public synchronized long nextId() {
long timestamp = this.timeGen();
if (this.lastTimestamp == timestamp) {
this.sequence = (this.sequence + 1) & this.sequenceMask;
if (this.sequence == 0) {
System.out.println("###########" + sequenceMask);
timestamp = this.tilNextMillis(this.lastTimestamp);
}
} else {
this.sequence = 0;
}
if (timestamp < this.lastTimestamp) {
try {
throw new Exception(
String.format(
"Clock moved backwards. Refusing to generate id for %d milliseconds",
this.lastTimestamp - timestamp));
} catch (Exception e) {
e.printStackTrace();
}
}
this.lastTimestamp = timestamp;
long nextId = ((timestamp - twepoch << timestampLeftShift))
| (this.workerId << this.workerIdShift) | (this.sequence);
System.out.println("timestamp:" + timestamp + ",timestampLeftShift:"
+ timestampLeftShift + ",nextId:" + nextId + ",workerId:"
+ workerId + ",sequence:" + sequence);
return nextId;
}
private long tilNextMillis(final long lastTimestamp) {
long timestamp = this.timeGen();
while (timestamp <= lastTimestamp) {
timestamp = this.timeGen();
}
return timestamp;
}
private long timeGen() {
return System.currentTimeMillis();
}
//調(diào)用
public static void main(String[] args){
IdWorker worker2 = new IdWorker(2);
System.out.println(worker2.nextId());
}
}