最近要用到这个, 仿造twitter的官方scala源码做了一个java版本. 因为是照着官方源码逐字翻译的, 所以和网上的其他版本大同小异, 并不是抄来的. 去掉了自定义sequence初始值的功能, 因为个人觉得用处不大; 并且出于性能考虑, 对几行代码做了inline处理, 所以代码比官方代码短一点.
源码:
/** * Snowflake java version. * From scala version at https://github.com/twitter/snowflake/releases/tag/snowflake-2010. * * Created by [email protected] on 2017/3/22. */ public class IdWorker implements IdGenerator { /*2017-01-01 00:00:00*/ private final long twepoch = 1483200000000L; private final long workerIdBits = 5L; private final long datacenterIdBits = 5L; private final long maxWorkerId = -1L ^ (-1L << workerIdBits); private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); private final long sequenceBits = 12L; private final long workerIdShift = sequenceBits; private final long datacenterIdShift = sequenceBits + workerIdBits; private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; private final long sequenceMask = -1L ^ (-1L << sequenceBits); private long workerId; private long datacenterId; private long sequence = 0L; private long lastTimestamp = -1L; public IdWorker(long workerId, long datacenterId) { 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; } public long getId() { return nextId(); } public synchronized long nextId() { long timestamp = System.currentTimeMillis(); if (timestamp < lastTimestamp) { throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp)); } if (lastTimestamp == timestamp) { sequence = (sequence + 1) & sequenceMask; if (sequence == 0) { timestamp = tilNextMillis(lastTimestamp); } } else { sequence = 0; } lastTimestamp = timestamp; return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence; } private long tilNextMillis(long lastTimestamp) { long timestamp = System.currentTimeMillis(); while (timestamp <= lastTimestamp) { timestamp = System.currentTimeMillis(); } return timestamp; } }
测试:
import org.testng.annotations.Test; /** * Test IdWorker * * Created by [email protected] on 2017/3/22. */ public class IdWorkerTest { @Test public void testGetId() { IdWorker idGenerator = new IdWorker(0, 0, 0); long start = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) { System.out.println(idGenerator.getId()); } System.out.println("Elapsed:" + (System.currentTimeMillis() - start)); } }
经测试, 在i3 CPU和"-Xmx64M"的环境下, 每毫秒生成260个左右. 幸好不是250.