import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class IdWorker {
protected static final Logger LOG = LoggerFactory.getLogger(IdWorker.class);
/**
* 每个节点的唯一数字ID
*/
private long workerId;
private long datacenterId;
private long sequence = 0L;
private long twepoch = 1288834974657L;
// 机器标识位数
private long workerIdBits = 5L;
// 数据中心标识位数
private long datacenterIdBits = 5L;
// 机器ID最大值
private long maxWorkerId = -1L ^ (-1L << workerIdBits);
// 数据中心ID最大值
private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
// 毫秒内自增位
private long sequenceBits = 12L;
// 机器ID偏左移12位
private long workerIdShift = sequenceBits;
// 数据中心ID左移17位
private long datacenterIdShift = sequenceBits + workerIdBits;
// 时间毫秒左移22位
private long timestampLeftShift = sequenceBits + workerIdBits+ datacenterIdBits;
private 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",maxWorkerId));
}
this.workerId = workerId;
}
public IdWorker(long workerId, long datacenterId) {
// sanity check for workerId
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0",maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0",maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
LOG.info(String.format("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d",timestampLeftShift, datacenterIdBits, workerIdBits,sequenceBits, workerId));
}
public synchronized long nextId() {
long timestamp = timeGen();
if (timestamp < lastTimestamp) {
LOG.error(String.format("clock is moving backwards. Rejecting requests until %d.",lastTimestamp));
throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds",lastTimestamp - timestamp));
}
if (lastTimestamp == timestamp) {
// 当前毫秒内,则+1
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
// 当前毫秒内计数满了,则等待下一秒
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
// ID偏移组合生成最终的ID,并返回ID
return ((timestamp - twepoch) << timestampLeftShift)| (datacenterId << datacenterIdShift)| (workerId << workerIdShift) | sequence;
}
// 等待下一个毫秒的到来
protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
protected long timeGen() {
return System.currentTimeMillis();
}
public static void main(String[] args) {
IdWorker idWorker = new IdWorker(1);
long orderId = idWorker.nextId();
System.out.println(orderId);
}
}
还有另外一种方式使用用户的编号+时间戮
http://www.oschina.net/question/865233_2137987
snowflake忽然想到一个问题,不能随便调整服务器的时间
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.net.NetworkInterface;
import java.util.Enumeration;
import java.util.Random;
/**
* 在分布式系统中,需要生成全局UID的场合还是比较多的,twitter的snowflake解决了这种需求,
* 实现也还是很简单的,除去配置信息,核心代码就是毫秒级时间41位+机器ID 10位+毫秒内序列12位。
* 该项目地址为:https://github.com/twitter/snowflake是用Scala实现的。
* Created by Administrator on 2016/3/31.
*/
public class IdWorker {
/**
* 根据具体机器环境提供
*/
private final long workerId;
/**
* 滤波器,使时间变小,生成的总位数变小,一旦确定不能变动
*/
private final static long twepoch = 1361753741828L;
private long sequence = 0L;
private final static long workerIdBits = 10L;
private final static long maxWorkerId = -1L ^ -1L << workerIdBits;
private final static long sequenceBits = 12L;
private final static long workerIdShift = sequenceBits;
private final static long timestampLeftShift = sequenceBits + workerIdBits;
private final static long sequenceMask = -1L ^ -1L << sequenceBits;
private long lastTimestamp = -1L;
/**
* 主机和进程的机器码
*/
private static IdWorker worker = new IdWorker();
private static final Log logger = LogFactory.getLog(IdWorker.class);
/**
* 主机和进程的机器码
*/
private static final int _genmachine;
static {
try {
// build a 2-byte machine piece based on NICs info
int machinePiece;
{
try {
StringBuilder sb = new StringBuilder();
Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
while ( e.hasMoreElements() ) {
NetworkInterface ni = e.nextElement();
sb.append(ni.toString());
}
machinePiece = sb.toString().hashCode() << 16;
} catch ( Throwable e ) {
// exception sometimes happens with IBM JVM, use random
logger.error(" IdWorker error. ", e);
machinePiece = new Random().nextInt() << 16;
}
logger.debug("machine piece post: " + Integer.toHexString(machinePiece));
}
// add a 2 byte process piece. It must represent not only the JVM
// but the class loader.
// Since static var belong to class loader there could be collisions
// otherwise
final int processPiece;
{
int processId = new java.util.Random().nextInt();
try {
processId = java.lang.management.ManagementFactory.getRuntimeMXBean().getName().hashCode();
} catch ( Throwable t ) {}
ClassLoader loader = IdWorker.class.getClassLoader();
int loaderId = loader != null ? System.identityHashCode(loader) : 0;
StringBuilder sb = new StringBuilder();
sb.append(Integer.toHexString(processId));
sb.append(Integer.toHexString(loaderId));
processPiece = sb.toString().hashCode() & 0xFFFF;
logger.debug("process piece: " + Integer.toHexString(processPiece));
}
_genmachine = machinePiece | processPiece;
logger.debug("machine : " + Integer.toHexString(_genmachine));
} catch ( Exception e ) {
throw new RuntimeException(e);
}
}
public IdWorker() {
workerId = _genmachine % (IdWorker.maxWorkerId + 1);
}
public static long getId() {
return worker.nextId();
}
public synchronized long nextId() {
long timestamp = timeGen();
if ( lastTimestamp == timestamp ) {
sequence = sequence + 1 & IdWorker.sequenceMask;
if ( sequence == 0 ) {
// System.out.println("###########" + sequenceMask);//等待下一毫秒
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0;
}
if ( timestamp < lastTimestamp ) {
try {
throw new Exception(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds",
lastTimestamp - timestamp));
} catch ( Exception e ) {
logger.error(" IdWorker error. ", e);
}
}
lastTimestamp = timestamp;
return timestamp - twepoch << timestampLeftShift | workerId << IdWorker.workerIdShift | sequence;
}
private long tilNextMillis( final long lastTimestamp1 ) {
long timestamp = timeGen();
while ( timestamp <= lastTimestamp1 ) {
timestamp = timeGen();
}
return timestamp;
}
private long timeGen() {
return System.currentTimeMillis();
}
}