Appearance
packagecom.leyou.common.utils;
importjava.lang.management.ManagementFactory;
importjava.net.InetAddress;
importjava.net.NetworkInterface;
_/**_
_*__\<p\>__名称:__IdWorker.java__\</p\>_
_*__\<p\>__描述:分布式自增长__ID__\</p\>_
_*__\<pre\>_
_*Twitter__的__SnowflakeJAVA__实现方案_
_*__\</pre\>_
_*__核心代码为其__IdWorker__这个类实现,其原理结构如下,我分别用一个__0__表示一位,用__—__分割开部分的作用:_
_*1||0---00000000000000000000000000000000000000000---00000---00000---000000000000_
_*__在上面的字符串中,第一位为未使用(实际上也可作为__long__的符号位),接下来的__41__位为毫秒级时间,_
_*__然后__5__位__datacenter__标识位,__5__位机器__ID__(并不算标识符,实际是为线程标识),_
_*__然后__12__位该毫秒内的当前毫秒内的计数,加起来刚好__64__位,为一个__Long__型。_
_*__这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生__ID__碰撞(由__datacenter__和机器__ID__作区分),_
_*__并且效率较高,经测试,__snowflake__每秒能够产生__26__万__ID__左右,完全满足需要。_
_*__\<p\>_
_*64__位__ID(42(__毫秒__)+5(__机器__ID)+5(__业务编码__)+12(__重复累加__))_
_*_
_*_**@author**_Polim_
_*/_
publicclassIdWorker{
//时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
privatefinalstaticlong_twepoch_=1288834974657L;
//机器标识位数
privatefinalstaticlong_workerIdBits_=5L;
//数据中心标识位数
privatefinalstaticlong_datacenterIdBits_=5L;
//机器ID最大值
privatefinalstaticlong_maxWorkerId_=-1L^(-1L\<\<_workerIdBits_);
//数据中心ID最大值
privatefinalstaticlong_maxDatacenterId_=-1L^(-1L\<\<_datacenterIdBits_);
//毫秒内自增位
privatefinalstaticlong_sequenceBits_=12L;
//机器ID偏左移12位
privatefinalstaticlong_workerIdShift_=_sequenceBits_;
//数据中心ID左移17位
privatefinalstaticlong_datacenterIdShift_=_sequenceBits_+_workerIdBits_;
//时间毫秒左移22位
privatefinalstaticlong_timestampLeftShift_=_sequenceBits_+_workerIdBits_+_datacenterIdBits_;
privatefinalstaticlong_sequenceMask_=-1L^(-1L\<\<_sequenceBits_);
/*上次生产id时间戳*/
privatestaticlong_lastTimestamp_=-1L;
//0,并发控制
privatelongsequence=0L;
privatefinallongworkerId;
//数据标识id部分
privatefinallongdatacenterId;
publicIdWorker(){
this.datacenterId=_getDatacenterId_(_maxDatacenterId_);
this.workerId=_getMaxWorkerId_(datacenterId,_maxWorkerId_);
}
_/**_
_*_**@param**_workerId_
_*__工作机器__ID_
_*_**@param**_datacenterId_
_*__序列号_
_*/_
publicIdWorker(longworkerId,longdatacenterId){
if(workerId\>_maxWorkerId_||workerId\<0){
thrownewIllegalArgumentException(String._format_("workerIdcan'tbegreaterthan%dorlessthan0",_maxWorkerId_));
}
if(datacenterId\>_maxDatacenterId_||datacenterId\<0){
thrownewIllegalArgumentException(String._format_("datacenterIdcan'tbegreaterthan%dorlessthan0",_maxDatacenterId_));
}
this.workerId=workerId;
this.datacenterId=datacenterId;
}
_/**_
_*__获取下一个__ID_
_*_
_*_**@return**
_*/_
publicsynchronizedlongnextId(){
longtimestamp=timeGen();
if(timestamp\<_lastTimestamp_){
thrownewRuntimeException(String._format_("Clockmovedbackwards.Refusingtogenerateidfor%dmilliseconds",_lastTimestamp_-timestamp));
}
if(_lastTimestamp_==timestamp){
//当前毫秒内,则+1
sequence=(sequence+1)&_sequenceMask_;
if(sequence==0){
//当前毫秒内计数满了,则等待下一秒
timestamp=tilNextMillis(_lastTimestamp_);
}
}else{
sequence=0L;
}
_lastTimestamp_=timestamp;
//ID偏移组合生成最终的ID,并返回ID
longnextId=((timestamp-_twepoch_)\<\<_timestampLeftShift_)
|(datacenterId\<\<_datacenterIdShift_)
|(workerId\<\<_workerIdShift_)|sequence;
returnnextId;
}
privatelongtilNextMillis(finallonglastTimestamp){
longtimestamp=this.timeGen();
while(timestamp\<=lastTimestamp){
timestamp=this.timeGen();
}
returntimestamp;
}
privatelongtimeGen(){
returnSystem._currentTimeMillis_();
}
_/**_
_*__\<p\>_
_*__获取__maxWorkerId_
_*__\</p\>_
_*/_
protectedstaticlonggetMaxWorkerId(longdatacenterId,longmaxWorkerId){
StringBuffermpid=newStringBuffer();
mpid.append(datacenterId);
Stringname=ManagementFactory._getRuntimeMXBean_().getName();
if(!name.isEmpty()){
/*
*GETjvmPid
*/
mpid.append(name.split("@")[0]);
}
/*
*MAC+PID的hashcode获取16个低位
*/
return(mpid.toString().hashCode()&0xffff)%(maxWorkerId+1);
}
_/**_
_*__\<p\>_
_*__数据标识__id__部分_
_*__\</p\>_
_*/_
protectedstaticlonggetDatacenterId(longmaxDatacenterId){
longid=0L;
try{
InetAddressip=InetAddress._getLocalHost_();
NetworkInterfacenetwork=NetworkInterface._getByInetAddress_(ip);
if(network==null){
id=1L;
}else{
byte[]mac=network.getHardwareAddress();
id=((0x000000FF&(long)mac[mac.length-1])
|(0x0000FF00&(((long)mac[mac.length-2])\<\<8)))\>\>6;
id=id%(maxDatacenterId+1);
}
}catch(Exceptione){
System._out_.println("getDatacenterId:"+e.getMessage());
}
returnid;
}
}