/** * Twitter_Snowflake<br> * SnowFlake following structure (with each section - apart): <br> * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000 <br> * An identity, as long basic types are signed in Java, the most significant bit is the sign bit, 0 is a positive number, a negative number is 1, so the id is generally positive, the highest bit is 0 <br> * 41 truncated time (milliseconds), it is noted than 41 times the cross-sectional cut-off storage time of the current time, but the difference between the storage time truncated (cut-off the current time - the start time of cut) * Value obtained), where the start time of a truncated, generally the time of our id generator is started, the program specified by our (the following procedure IdWorker class attributes startTime below). Cut-off time 41, 69 may be used in, in T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69 <br> * 10 data bits machines, nodes may be deployed in 1024, and comprises five datacenterId 5 workerId <br> * 12 bit sequence, the count within milliseconds, the count of sequence number 12 of each support node per millisecond (the same machine, the same cut-off time) to produce the ID number 4096 <br> * Add up to just 64 for a Long type. <br> * Snowflake advantage is that the overall increment in time order, and do not generate collisions ID (as distinguished from the data center ID and machine ID) throughout the distributed system, and high efficiency, tested, can be generated per second Snowflake about 260,000 ID. */ public class SnowflakeIdWorker { // ============================== Fields ================= ========================== / ** start time cut (2015-01-01) * / Private Final Long twepoch = 1420041600000L ; / ** -digit share of the machine id * / Private Final Long workerIdBits = 5L ; / * Data identifying the number of bits occupied by the ID * / Private Final Long datacenterIdBits = 5L ; / ** The maximum supported machine id, the result is 31 (this shift algorithm can quickly calculate the maximum number of decimal several binary number can represent) * / Private Final Long maxWorkerId -1L = ^ (-1L << workerIdBits); / ** The maximum data identification id, result 31 is * / Private Final Long maxDatacenterId -1L = ^ (-1L << datacenterIdBits); / * Sequence number of bits occupied in id * / Private Final Long sequenceBits = 12L ; / ** machine ID 12 to the left * / Private Final Long workerIdShift = sequenceBits; / * Data identifying id to the left by 17 (+ 12 is. 5) * / Private Final Long datacenterIdShift + = sequenceBits workerIdBits; / * Time to cut the left 22 (. 5 + + 12 is. 5) * / Private Final Long timestampLeftShift workerIdBits + + = sequenceBits datacenterIdBits; / ** generating a mask sequence, here 4095 (0b111111111111 = 0xFFF = 4095) * / Private Final Long sequenceMask -1L = ^ (-1L << sequenceBits); / ** Work machine ID (~ 31 is 0) * / Private Long workerId; / ** Data Center ID (~ 31 is 0) * / Private Long datacenterId; / ** milliseconds sequence (0 ~ 4095) * / Private Long Sequence = 0L ; / * Last generated ID sectional time * / Private Long LastTimestamp = -1L ; //==============================Constructors===================================== /** * Constructor * @Param workerId Job ID (0 ~ 31) * @param datacenterId 数据中心ID (0~31) */ public SnowflakeIdWorker(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; } // ==============================Methods========================================== /** * Get the next ID (which is thread-safe) * @return SnowflakeId */ public synchronized long nextId() { long timestamp = timeGen(); // if the current time is less than the timestamp of the last generation ID, indicating the system clock backoff time should be thrown through the IF (timestamp < LastTimestamp) { the throw new new a RuntimeException ( String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp)); } // If it is generated at the same time, the sequence is performed within milliseconds IF (LastTimestamp == timestamp) { Sequence = (+ Sequence. 1) & sequenceMask; // millisecond sequence overflow IF (Sequence == 0 ) { // blocking the next millisecond, obtain a new timestamp timestamp = tilNextMillis (LastTimestamp); } } // time stamp change, the sequence milliseconds reset the else { sequence = 0L; } // Last time generation ID sectional LastTimestamp = timestamp; // shift to the fight and ORed with the composition 64 ID return ((timestamp - twepoch) << timestampLeftShift) // | (datacenterId << datacenterIdShift) // | (workerId << workerIdShift) // | Sequence; } /** * Blocking a millisecond to the next, until a new timestamp * @Param LastTimestamp cut-off time of the last generation ID * @Return current timestamp * / protected Long tilNextMillis ( Long LastTimestamp) { Long timestamp = TIMEGEN (); the while (timestamp <= LastTimestamp) { timestamp = timeGen(); } return timestamp; } /** * Returns the current time in milliseconds * @Return current time (ms) * / protected Long TIMEGEN () { return System.currentTimeMillis (); } // ============================== the Test ================= ============================ / ** test * / public static void main (String [] args) { SnowflakeIdWorker idWorker = new SnowflakeIdWorker(0, 0); for (int i = 0; i < 1000; i++) { long id = idWorker.nextId(); System.out.println(Long.toBinaryString(id)); System.out.println(id); } } }