1. 程式人生 > 其它 >生成4位隨機數

生成4位隨機數

本來是用隨機演算法的,但是會有重複,花了點時間研究了下,發現雪花演算法好似不會重複,

程式碼如下:

package com.excel.test;

import java.util.concurrent.atomic.AtomicInteger;

public class MinuteCounter {
    private static final int MASK = 0x7FFFFFFF;
    private final AtomicInteger atom;
    
    public MinuteCounter() {
        atom = new AtomicInteger(0);
    }
    
    
public final int incrementAndGet() { return atom.incrementAndGet() & MASK; } public int get() { return atom.get() & MASK; } public void set(int newValue) { atom.set(newValue & MASK); } }
package com.excel.test;

/**
 * 此方式只適用於一個單體應用,不適合分散式系統
 *
 *  將產生的Id型別更改為Integer 32bit <br>
 *  把時間戳的單位改為分鐘,使用25個位元的時間戳(分鐘) <br>
 *  去掉機器ID和資料中心ID <br>
 *  7個位元作為自增值,即2的7次方等於128。
 *
 */
public class SnowflakeIdWorker3rd {
    /** 開始時間戳 (2019-01-01) */
    private final int twepoch = 25771200;// 1546272000000L/1000/60;

    /** 序列在id中佔的位數 */
    private final long sequenceBits = 7L;

    /** 時間截向左移7位 */
    private final long timestampLeftShift = sequenceBits;

    /** 生成序列的掩碼,這裡為127 */
    private final int sequenceMask = -1 ^ (-1 << sequenceBits);

    /** 分鐘內序列(0~127) */
    private int sequence = 0;
    private int laterSequence = 0;

    /** 上次生成ID的時間戳 */
    private int lastTimestamp = -1;

    private final MinuteCounter counter = new MinuteCounter();
    
    /** 預支時間標誌位 */
    boolean isAdvance = false;

    // ==============================Constructors=====================================
    public SnowflakeIdWorker3rd() {

    }

    // ==============================Methods==========================================
    /**
     * 獲得下一個ID (該方法是執行緒安全的)
     * 
     * @return SnowflakeId
     */
    public synchronized int nextId() {
        
        
        int timestamp = timeGen();
        // 如果當前時間小於上一次ID生成的時間戳,說明系統時鐘回退過這個時候應當丟擲異常
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(String.format(
                    "Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }
        
        if(timestamp > counter.get()) {
            counter.set(timestamp);
            isAdvance = false;
        }

        // 如果是同一時間生成的,則進行分鐘內序列
        if (lastTimestamp == timestamp || isAdvance) {
            if(!isAdvance) {
                sequence = (sequence + 1) & sequenceMask;
            }

            // 分鐘內自增列溢位
            if (sequence == 0) {
                // 預支下一個分鐘,獲得新的時間戳
                isAdvance = true;
                int laterTimestamp = counter.get();
                if (laterSequence == 0) {
                    laterTimestamp = counter.incrementAndGet();
                }

                int nextId = ((laterTimestamp - twepoch) << timestampLeftShift) //
                        | laterSequence;
                laterSequence = (laterSequence + 1) & sequenceMask;
                return nextId;
            }
        }
        // 時間戳改變,分鐘內序列重置
        else {
            sequence = 0;
            laterSequence = 0;
        }

        // 上次生成ID的時間截
        lastTimestamp = timestamp;

        // 移位並通過或運算拼到一起組成32位的ID
        return ((timestamp - twepoch) << timestampLeftShift) //
                | sequence;
    }

    /**
     * 返回以分鐘為單位的當前時間
     * 
     * @return 當前時間(分鐘)
     */
    protected int timeGen() {
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000 / 60);
        return Integer.valueOf(timestamp);
    }

}

  

測試類

package com.excel.test;

import java.util.HashSet;
import java.util.Set;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        SnowflakeIdWorker3rd worker3rd = new SnowflakeIdWorker3rd();

        Set<Integer> set = new HashSet<>();

        
for (int j = 0; j < 50; j++) { for (int i = 0; i < 100; i++) { int l = worker3rd.nextId();//% 10000; Thread.sleep(10); set.add(l); } System.out.println(set.size()); } } }