Maison  >  Article  >  Java  >  Comment l’algorithme du flocon de neige génère-t-il les identifiants ?

Comment l’algorithme du flocon de neige génère-t-il les identifiants ?

coldplay.xixi
coldplay.xixioriginal
2020-08-31 13:15:5214212parcourir

La méthode de génération d'identifiant par l'algorithme de flocon de neige : créez d'abord une nouvelle classe pour la génération d'identifiant ; puis créez un nouvel outil singleton qui appelle l'identifiant généré et enfin, utilisez la fonction [GuuidUtil.getUUID()] pour appeler ; directement.

Comment l’algorithme du flocon de neige génère-t-il les identifiants ?

[Recommandations d'apprentissage associées : bases de Java]

La méthode de génération d'identifiant par l'algorithme snowflake :

1 Créez une nouvelle classe générée par identifiant SnowFlake

/**
 * @Auther: lyl
 * @Date: 2019/11/21 17:49
 * @Description:
 */
public class SnowFlake {
    /**
     * 起始的时间戳
     */
    private final static long START_STMP = 1480166465631L;
    /**
     * 每一部分占用的位数
     */
    private final static long SEQUENCE_BIT = 12; //序列号占用的位数
    private final static long MACHINE_BIT = 5;  //机器标识占用的位数
    private final static long DATACENTER_BIT = 5;//数据中心占用的位数
    /**
     * 每一部分的最大值
     */
    private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);
    private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
    private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);
    /**
     * 每一部分向左的位移
     */
    private final static long MACHINE_LEFT = SEQUENCE_BIT;
    private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
    private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;
    private long datacenterId;  //数据中心
    private long machineId;    //机器标识
    private long sequence = 0L; //序列号
    private long lastStmp = -1L;//上一次时间戳
    public SnowFlake(long datacenterId, long machineId) {
        if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
            throw new IllegalArgumentException("datacenterId can&#39;t be greater than MAX_DATACENTER_NUM or less than 0");
        }
        if (machineId > MAX_MACHINE_NUM || machineId < 0) {
            throw new IllegalArgumentException("machineId can&#39;t be greater than MAX_MACHINE_NUM or less than 0");
        }
        this.datacenterId = datacenterId;
        this.machineId = machineId;
    }
    /**
     * 产生下一个ID
     *
     * @return
     */
    public synchronized long nextId() {
        long currStmp = getNewstmp();
        if (currStmp < lastStmp) {
            throw new RuntimeException("Clock moved backwards.  Refusing to generate id");
        }
        if (currStmp == lastStmp) {
            //相同毫秒内,序列号自增
            sequence = (sequence + 1) & MAX_SEQUENCE;
            //同一毫秒的序列数已经达到最大
            if (sequence == 0L) {
                currStmp = getNextMill();
            }
        } else {
            //不同毫秒内,序列号置为0
            sequence = 0L;
        }
        lastStmp = currStmp;
        return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分
                | datacenterId << DATACENTER_LEFT      //数据中心部分
                | machineId << MACHINE_LEFT            //机器标识部分
                | sequence;                            //序列号部分
    }
    private long getNextMill() {
        long mill = getNewstmp();
        while (mill <= lastStmp) {
            mill = getNewstmp();
        }
        return mill;
    }
    private long getNewstmp() {
        return System.currentTimeMillis();
    }
    public static void main(String[] args) {
        SnowFlake snowFlake = new SnowFlake(2, 3);
        for (int i = 0; i < (1 << 12); i++) {
            System.out.println(snowFlake.nextId());
        }
    }
}

2 Pour empêcher plusieurs threads de générer des identifiants en double, un. un nouveau est créé ici Un outil singleton qui appelle pour générer un identifiant

où machineId et datacenterId peuvent être placés dans le fichier de configuration

import java.util.concurrent.CountDownLatch;
/**
 * @Auther: lyl
 * @Date: 2019/11/21 18:15
 * @Description:
 */
public class GuuidUtil {
    private static long machineId = 0;
    private static long datacenterId = 0;
    /**
     * 单例模式创建学法算法对象
     * */
    private enum SnowFlakeSingleton{
        Singleton;
        private SnowFlake snowFlake;
        SnowFlakeSingleton(){
            snowFlake = new SnowFlake(datacenterId,machineId);
        }
        public SnowFlake getInstance(){
            return snowFlake;
        }
    }
    public static long getUUID(){
        return SnowFlakeSingleton.Singleton.getInstance().nextId();
    }
    public static void main(String[] args) {
         CountDownLatch latch = new CountDownLatch(10000);
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            new Runnable() {
                @Override
                public void run() {
                    System.out.println(GuuidUtil.getUUID());
                    latch.countDown();
                }
            }.run();
        }
        try {
            System.out.println("主线程"+Thread.currentThread().getName()+"等待子线程执行完成...");
            latch.await();//阻塞当前线程,直到计数器的值为0
            System.out.println("主线程"+Thread.currentThread().getName()+"开始执行...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.print("雪花算法用时: ");
        System.out.println(System.currentTimeMillis() - start);
    }
}

Enfin, appelez directement : GuuidUtil.getUUID() ;

Si vous souhaitez en savoir plus sur la programmation, faites attention à la rubrique Formation php !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn