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

com.github.azbh111.utils.java.uid.DefaultUidGenerator Maven / Gradle / Ivy

The newest version!
package com.github.azbh111.utils.java.uid;

import com.github.azbh111.utils.java.date.DateUtils;
import com.github.azbh111.utils.java.datetime.DateTimeUtils;

import java.time.LocalDate;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @author: zyp
 * @date: 2020/8/24 4:51 下午
 */
public class DefaultUidGenerator implements UidGenerator {

    /**
     * Customer epoch, unit as second. For example 2016-05-20 (ms: 1463673600000)
     */
//    起始时间
    protected long epochSeconds = TimeUnit.MILLISECONDS.toSeconds(1463673600000L);

    /**
     * Stable fields after spring bean initializing
     */
    protected BitsAllocator bitsAllocator;
    protected long workerId;

    /**
     * Volatile fields caused by nextId()
     */
    protected long sequence = 0L;
    protected long lastSecond = -1L;



    @Override
    public long getUID() throws UidGenerateException {
        try {
            return nextId();
        } catch (Exception e) {
            throw new UidGenerateException(e);
        }
    }

    @Override
    public String parseUID(long uid) {
        long totalBits = BitsAllocator.TOTAL_BITS;
        long signBits = bitsAllocator.getSignBits();
        long timestampBits = bitsAllocator.getTimestampBits();
        long workerIdBits = bitsAllocator.getWorkerIdBits();
        long sequenceBits = bitsAllocator.getSequenceBits();

        // parse UID
        long sequence = (uid << (totalBits - sequenceBits)) >>> (totalBits - sequenceBits);
        long workerId = (uid << (timestampBits + signBits)) >>> (totalBits - workerIdBits);
        long deltaSeconds = uid >>> (workerIdBits + sequenceBits);

        Date thatTime = new Date(TimeUnit.SECONDS.toMillis(epochSeconds + deltaSeconds));
        String thatTimeStr = DateTimeUtils.format(thatTime, "yyyy-MM-dd HH:mm:ss");

        // format as string
        return String.format("{\"UID\":\"%d\",\"timestamp\":\"%s\",\"workerId\":\"%d\",\"sequence\":\"%d\"}",
                uid, thatTimeStr, workerId, sequence);
    }

    /**
     * Get UID
     *
     * @return UID
     * @throws UidGenerateException in the case: Clock moved backwards; Exceeds the max timestamp
     */
    protected synchronized long nextId() {
        long currentSecond = getCurrentSecond();

        // Clock moved backwards, refuse to generate uid
        if (currentSecond < lastSecond) {
            long refusedSeconds = lastSecond - currentSecond;
            throw new UidGenerateException("Clock moved backwards. Refusing for %d seconds", refusedSeconds);
        }

        // At the same second, increase sequence
        if (currentSecond == lastSecond) {
            sequence = (sequence + 1) & bitsAllocator.getMaxSequence();
            // Exceed the max sequence, we wait the next second to generate uid
            if (sequence == 0) {
                currentSecond = getNextSecond(lastSecond);
            }

            // At the different second, sequence restart from zero
        } else {
            sequence = 0L;
        }

        lastSecond = currentSecond;

        // Allocate bits for UID
        return bitsAllocator.allocate(currentSecond - epochSeconds, workerId, sequence);
    }

    /**
     * Get next millisecond
     */
    private long getNextSecond(long lastTimestamp) {
        long timestamp = getCurrentSecond();
        while (timestamp <= lastTimestamp) {
            timestamp = getCurrentSecond();
        }

        return timestamp;
    }

    /**
     * Get current second
     */
    private long getCurrentSecond() {
        long currentSecond = System.currentTimeMillis() / 1000;
        if (currentSecond - epochSeconds > bitsAllocator.getMaxDeltaSeconds()) {
            throw new UidGenerateException("Timestamp bits is exhausted. Refusing UID generate. Now: " + currentSecond);
        }

        return currentSecond;
    }

    public static class DefaultUidGeneratorBuilder {
        /**
         * Bits allocate
         */
        private int timeBits = 28;
        private int workerBits = 22;
        private int seqBits = 13;
        //    起始日期 2020-01-01
        private LocalDate epochSecondsStart = LocalDate.of(2020, 1, 1);
        private long workerId;

        public UidGenerator build() {
            DefaultUidGenerator g = new DefaultUidGenerator();
            if (timeBits + workerBits + seqBits > 63) {
                throw new UidGenerateException("bits can not be greater than 63");
            }
            if (timeBits + workerBits + seqBits < 63) {
//                自动设置timeBits
                timeBits = 63 - workerBits - seqBits;
            }
            g.bitsAllocator = new BitsAllocator(timeBits, workerBits, seqBits);
            g.epochSeconds = DateUtils.toDate(epochSecondsStart).getTime() / 1000;
            g.workerId = workerId;
            return g;
        }

        /**
         * 设置最大节点数
         *
         * @param maxIds
         * @return
         */
        public DefaultUidGeneratorBuilder setMaxWorkers(int maxWorkers) {
            int bits = 1;
            while ((1 << bits) - 1 < maxWorkers) {
                bits++;
            }
            this.workerBits = bits;
            return this;
        }

        /**
         * 每秒能生成的id数
         *
         * @param maxIds
         * @return
         */
        public DefaultUidGeneratorBuilder setMaxIdInSeconds(int maxIds) {
            int bits = 1;
            while ((1 << bits) - 1 < maxIds) {
                bits++;
            }
            this.seqBits = bits;
            return this;
        }

        public DefaultUidGeneratorBuilder setTimeBits(int timeBits) {
            this.timeBits = timeBits;
            return this;
        }

        public DefaultUidGeneratorBuilder setWorkerBits(int workerBits) {
            this.workerBits = workerBits;
            return this;
        }

        public DefaultUidGeneratorBuilder setSeqBits(int seqBits) {
            this.seqBits = seqBits;
            return this;
        }

        public DefaultUidGeneratorBuilder setEpochSecondsStart(LocalDate epochSecondsStart) {
            this.epochSecondsStart = epochSecondsStart;
            return this;
        }

        public DefaultUidGeneratorBuilder setWorkerId(long workerId) {
            this.workerId = workerId;
            return this;
        }

        public int getTimeBits() {
            return timeBits;
        }

        public int getWorkerBits() {
            return workerBits;
        }

        public int getSeqBits() {
            return seqBits;
        }

        public LocalDate getEpochSecondsStart() {
            return epochSecondsStart;
        }

        public long getWorkerId() {
            return workerId;
        }
    }

    public static DefaultUidGeneratorBuilder builder() {
        return new DefaultUidGeneratorBuilder();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy