- 參考snowflake算法,基本思路:
-
序列12位(更格式化的輸出后,性能損耗導致每毫秒生成不了這么多,所以可以考慮減少這里的位,不過留着也並無影響)
-
機器位10位
-
毫秒為左移 22位
-
上述幾個做或運算后得出一個唯一的數,轉10進制后,最大10位,最小7位,string.format來統一為10,format性能影響,導致性能降低3倍左右
FilUtils不想用的話,1太機器可以直接考慮使用1,多機器根據代碼配置id
代碼如下:
package net.gitosc.lianqu1990.utils.code;
import net.gitosc.lianqu1990.utils.date.DateFormatUtils;
import net.gitosc.lianqu1990.utils.date.TimeMark;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
/**
* 缺陷是,訂單量沒那么大,導致機器碼|序列 后,一般都是4096
* 通過將毫秒引入序列后修正
* 后來加了format以后性能受損,比idcenter慢10倍,每秒可以生成50w,idcenter將近500w,不過這也是idcenter極限
* 夠用,暫不優化
* @author hanchao
* @date 2017/4/20 19:01
*/
public class OrderNoCenter {
public static final Logger logger = LoggerFactory.getLogger(OrderNoCenter.class);
private static final String WORKERID_PATH = "/etc/workerId";
private OrderNoCenter() {
}
private static class OrderNoCenterHolder{
private static OrderNoCenter instance = new OrderNoCenter();
}
public static OrderNoCenter getInstance() {
return OrderNoCenterHolder.instance;
}
/**
* 節點 ID 默認取1
*/
private long workerId = 1;
/**
* 序列id 默認取1
*/
private long sequence = 1;
/**
* 機器標識位數
*/
private final long workerIdBits = 10L;
/**
* 機器ID最大值
*/
private final long maxWorkerId = -1L ^ (-1L << workerIdBits); //結果就是2的workerBits次方-1,能表示的最大數.全部1亦或10位0,就是0開頭最后10位1
/**
* 毫秒內自增位
*/
private final long sequenceBits = 12L;
/**
* 機器ID偏左移12位
*/
private final long workerIdShift = sequenceBits;
/**
* 數據中心ID左移17位
*/
private final long datacenterIdShift = sequenceBits + workerIdBits;
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
/**
* 時間毫秒左移22位
*/
private final long timestampLeftShift = sequenceBits + workerIdBits;
private long lastTimestamp = -1L;
public void initParam() {
// 從默認位置讀取workerId,最大1024
try {
File conf = new File(WORKERID_PATH);
if(conf.exists()){
String str = FileUtils.readFileToString(conf);
workerId = Integer.parseInt(str);
}else{
logger.warn(" worker id not found,will use default value...");
}
} catch(Exception e){
e.printStackTrace();
}
logger.info(" worker id is {}",workerId);
if (workerId < 0 || workerId > maxWorkerId) {
throw new IllegalArgumentException("workerId is illegal: "
+ workerId);
}
}
public long getWorkerId() {
return workerId;
}
public long getTime() {
return System.currentTimeMillis();
}
public String create() {
return nextNo();
}
/**
* 獲取id 線程安全
*
* @return
*/
private synchronized String nextNo() {
long timestamp = timeGen();
// 時間錯誤
if (timestamp < lastTimestamp) {
throw new IllegalStateException("Clock moved backwards.");
}
// 當前毫秒內,則+1
if (lastTimestamp == timestamp) {
// 當前毫秒內計數滿了,則等待下一秒
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0;
}
lastTimestamp = timestamp;
// ID偏移組合生成最終的ID,並返回ID,最大十位數
long id = ((timestamp % 1000) << timestampLeftShift) | (workerId << workerIdShift) | sequence;
String timestampStr = DateFormatUtils.NUMBER_FORMAT.format(timestamp);
return timestampStr+String.format("%010d",id);
}
/**
* 等待下一個毫秒的到來
*
* @param lastTimestamp
* @return
*/
private long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
private long timeGen() {
return System.currentTimeMillis();
}
/**
* 最大十位,最小7位,補0format
*/
/*public void test(){
String t = String.valueOf((1L << 22) | (1 << 12) | 0);
String t1 = String.valueOf((999L << 22) | (1023 << 12) | 0);
System.out.println(DateFormatUtils.NUMBER_FORMAT.format(System.currentTimeMillis())+"-"+t);
System.out.println(DateFormatUtils.NUMBER_FORMAT.format(System.currentTimeMillis())+"-"+t1);
long l1 = (1L << 22) | (1 << 12) | 0;
long l2 = (999L << 22) | (1023 << 12) | 0;
System.out.println(l1);
System.out.println(l2);
System.out.println(String.format("%010d",l1));
System.out.println(String.format("%010d",l2));
}*/
public static void main(String[] args){
for (int i = 0; i < 100; i++) {
System.out.println(OrderNoCenter.getInstance().create());
}
//性能測試
TimeMark mark = new TimeMark();
for (int i = 0; i < 1000000; i++) {
OrderNoCenter.getInstance().create();
}
mark.simplePrint();
mark.mark();
for (int i = 0; i < 1000000; i++) {
IdCenter.getInstance().getId();
}
mark.simplePrint();
}
}
缺少代碼的話,請直接使用我的附件代碼
附件:
代碼代碼代碼代碼代碼點擊下載下載