All Downloads are FREE. Search and download functionalities are using the official Maven repository.

space.chensheng.wsmessenger.common.util.SnowFlakeIdGenerator Maven / Gradle / Ivy

The newest version!
package space.chensheng.wsmessenger.common.util;

/**
 * 
 * Generate long type ID. The composition of id is 1bit-41bit-10bit-12bit. 
 * The 1bit is 0 which means to generate positive id value. 
 * The 41bit is the diff between current time millis and id generating start time millis.
 * The 10bit is the machine id.
 * The 12bit is the sequence.
 *
 */
public class SnowFlakeIdGenerator {
	private final long twepoch;
	
	private final long machineId;
	
	private long sequence = 0L;
	
	private final long machineIdBits = 10L;
	
	private final long sequenceBits = 12L;
	
	private final long maxMachineId = -1L ^ (-1L << machineIdBits);
	
	private final long sequenceMask = -1L ^ (-1L << sequenceBits);
	
	private final long machineIdShift = sequenceBits;
	
	private final long elapsedTimeMillisShift = machineIdBits + sequenceBits;

	private long lastElapsedTimeMillis = -1L;
	
	public SnowFlakeIdGenerator(long machineId, long twepoch) {
		if (machineId < 0) {
			throw new IllegalArgumentException("machineId must not be negative");
		}
		
		if (machineId > maxMachineId) {
			throw new IllegalArgumentException("machineId must be less than " + (maxMachineId + 1));
		}
		
		if (twepoch > System.currentTimeMillis()) {
            throw new IllegalArgumentException("twepoch must not be greater than current time milliseconds");
		}
		
		this.machineId = maxMachineId;
		this.twepoch  = twepoch ;
	}
	
	public synchronized long nextId() {
		long elapsedTimeMillis = getElapsedTimeMillis();
		if (elapsedTimeMillis < lastElapsedTimeMillis) {
			throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d elapsed milliseconds", elapsedTimeMillis));
		}

        if (elapsedTimeMillis == lastElapsedTimeMillis) {
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                elapsedTimeMillis = tillNextElapsedTime();
            }
        } else {
            sequence = 0L;
        }

        lastElapsedTimeMillis = elapsedTimeMillis;
		
		return (elapsedTimeMillis << elapsedTimeMillisShift) | (machineId << machineIdShift) | sequence;
	}
	
	private long getElapsedTimeMillis() {
		return System.currentTimeMillis() - twepoch;
	}

    private long tillNextElapsedTime() {
	    long nextElapsedTimeMillis = getElapsedTimeMillis();
	    while (nextElapsedTimeMillis <= lastElapsedTimeMillis) {
	        nextElapsedTimeMillis = getElapsedTimeMillis();
	    }
	    return nextElapsedTimeMillis;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy