Created
June 28, 2017 08:51
-
-
Save xishuixixia/f0f8684805d0504289b7a40f3b327dd6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.rrjc.pf.common; | |
import java.net.InetAddress; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
/** | |
* (a) id构成: 42位的时间前缀 + 10位的节点标识 + 12位的sequence避免并发的数字(12位不够用时强制得到新的时间前缀) | |
* 注意这里进行了小改动: snowkflake是5位的datacenter加5位的机器id; 这里变成使用10位的机器id | |
* (b) 对系统时间的依赖性非常强,需关闭ntp的时间同步功能。当检测到ntp时间调整后,将会拒绝分配id | |
*/ | |
public class IdWorker { | |
private final static Logger logger = LoggerFactory.getLogger(IdWorker.class); | |
private final long workerId; | |
private final long epoch = 1403854494756L; // 时间起始标记点,作为基准,一般取系统的最近时间 | |
private final long workerIdBits = 10L; // 机器标识位数 | |
private final long maxWorkerId = -1L ^ -1L << this.workerIdBits;// 机器ID最大值: 1023 | |
private long sequence = 0L; // 0,并发控制 | |
private final long sequenceBits = 12L; //毫秒内自增位 | |
private final long workerIdShift = this.sequenceBits; // 12 | |
private final long timestampLeftShift = this.sequenceBits + this.workerIdBits;// 22 | |
private final long sequenceMask = -1L ^ -1L << this.sequenceBits; // 4095,111111111111,12位 | |
private long lastTimestamp = -1L; | |
private IdWorker(long workerId) { | |
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() throws Exception { | |
long timestamp = IdWorker.timeGen(); | |
if (this.lastTimestamp == timestamp) { // 如果上一个timestamp与新产生的相等,则sequence加一(0-4095循环); 对新的timestamp,sequence从0开始 | |
this.sequence = this.sequence + 1 & this.sequenceMask; | |
if (this.sequence == 0) { | |
timestamp = this.tilNextMillis(this.lastTimestamp);// 重新生成timestamp | |
} | |
} else { | |
this.sequence = 0; | |
} | |
if (timestamp < this.lastTimestamp) { | |
logger.error(String.format("clock moved backwards.Refusing to generate id for %d milliseconds", (this.lastTimestamp - timestamp))); | |
throw new Exception(String.format("clock moved backwards.Refusing to generate id for %d milliseconds", (this.lastTimestamp - timestamp))); | |
} | |
this.lastTimestamp = timestamp; | |
return timestamp - this.epoch << this.timestampLeftShift | this.workerId << this.workerIdShift | this.sequence; | |
} | |
private static IdWorker flowIdWorker = new IdWorker(getworkerHostIp()); | |
public static IdWorker getFlowIdWorkerInstance() { | |
return flowIdWorker; | |
} | |
/** | |
* 等待下一个毫秒的到来, 保证返回的毫秒数在参数lastTimestamp之后 | |
*/ | |
private long tilNextMillis(long lastTimestamp) { | |
long timestamp = IdWorker.timeGen(); | |
while (timestamp <= lastTimestamp) { | |
timestamp = IdWorker.timeGen(); | |
} | |
return timestamp; | |
} | |
/** | |
* 获得系统当前毫秒数 | |
*/ | |
private static long timeGen() { | |
return System.currentTimeMillis(); | |
} | |
/** | |
* | |
* @param bytes | |
* @return int | |
*/ | |
public static int getworkerHostIp() { | |
try { | |
byte[] bytes = InetAddress.getLocalHost().getAddress(); | |
return Integer.valueOf(bytes[3] & 0xFF); | |
} catch (Exception e) { | |
logger.error(e.getMessage(),e); | |
return 1; | |
} | |
} | |
public static void main(String[] args) throws Exception { | |
IdWorker idWorker = IdWorker.getFlowIdWorkerInstance(); | |
System.out.println(idWorker.nextId()); | |
System.out.println(idWorker.nextId()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
48行是不是应该改成
return (timestamp - this.epoch )<< this.timestampLeftShift | this.workerId << this.workerIdShift | this.sequence;
,其中this.workerId << this.workerIdShift
可以作为final变量存储,不用每次计算吧