欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java生成訂單號(hào)或唯一id的高并發(fā)方案(4種方法)

 更新時(shí)間:2024年01月22日 15:54:06   作者:吳名氏.  
本文主要介紹了Java生成訂單號(hào)或唯一id的高并發(fā)方案,包括4種方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

1、直接使用uuid

public static String getUUID() {
        String replaceUUID = UUID.randomUUID().toString().replace("-", "");
        return replaceUUID;
    }

但由于生成的數(shù)據(jù)沒(méi)有規(guī)律性,并且太長(zhǎng);

測(cè)試:循環(huán)1000w次

測(cè)試代碼:

    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        Set set=new HashSet<>();
        for(int i=0;i<10000000;i++){
            String uuid = getUUID();
            System.out.println("uuid---"+i+"======="+uuid);
            set.add(uuid);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("set.size():"+set.size());
        System.out.println("endTime-startTime:"+(endTime-startTime));
    }

控制臺(tái)提示:

2、用時(shí)間(精確到毫秒)+隨機(jī)數(shù)

         //時(shí)間(精確到毫秒)
        DateTimeFormatter ofPattern = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
        String localDate = LocalDateTime.now().format(ofPattern);
        //隨機(jī)數(shù)
        String randomNumeric = RandomStringUtils.randomNumeric(8);

for循環(huán)1000w次,發(fā)現(xiàn)重復(fù)數(shù)據(jù)太多。因此光靠隨機(jī)數(shù)并不可靠。

3、使用 時(shí)間(精確到毫秒)+隨機(jī)數(shù)+用戶id(業(yè)務(wù)id)

注意:如果是類似用戶id,項(xiàng)目當(dāng)中集成了權(quán)限框架,使用工具類獲取即可,就不用傳參了

   /**
     * 生成訂單號(hào)(25位):時(shí)間(精確到毫秒)+3位隨機(jī)數(shù)+5位用戶id
     */
    public static synchronized  String getOrderNum(Long userId) {
        //時(shí)間(精確到毫秒)
        DateTimeFormatter ofPattern = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
        String localDate = LocalDateTime.now().format(ofPattern);
        //3位隨機(jī)數(shù)
        String randomNumeric = RandomStringUtils.randomNumeric(3);
        //5位用戶id
        int subStrLength = 5;
        String sUserId = userId.toString();
        int length = sUserId.length();
        String str;
        if (length >= subStrLength) {
            str = sUserId.substring(length - subStrLength, length);
        } else {
            str = String.format("%0" + subStrLength + "d", userId);
        }
        String orderNum = localDate + randomNumeric + str;
        log.info("訂單號(hào):{}", orderNum);
        return orderNum;
    }

在2的基礎(chǔ)上改造,加入用戶的id等其他的業(yè)務(wù)id。

4.Java實(shí)現(xiàn)Snowflake算法的方案(高并發(fā)下,推薦使用這個(gè))

package com.lucifer.order.util.idgenerate;
 
/**
 * Twitter_Snowflake<br>
 * SnowFlake的結(jié)構(gòu)如下(每部分用-分開):<br>
 * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000 <br>
 * 1位標(biāo)識(shí),由于long基本類型在Java中是帶符號(hào)的,最高位是符號(hào)位,正數(shù)是0,負(fù)數(shù)是1,所以id一般是正數(shù),最高位是0<br>
 * 41位時(shí)間截(毫秒級(jí)),注意,41位時(shí)間截不是存儲(chǔ)當(dāng)前時(shí)間的時(shí)間截,而是存儲(chǔ)時(shí)間截的差值(當(dāng)前時(shí)間截 - 開始時(shí)間截)
 * 得到的值),這里的的開始時(shí)間截,一般是我們的id生成器開始使用的時(shí)間,由我們程序來(lái)指定的(如下下面程序IdWorker類的startTime屬性)。41位的時(shí)間截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69<br>
 * 10位的數(shù)據(jù)機(jī)器位,可以部署在1024個(gè)節(jié)點(diǎn),包括5位datacenterId和5位workerId<br>
 * 12位序列,毫秒內(nèi)的計(jì)數(shù),12位的計(jì)數(shù)順序號(hào)支持每個(gè)節(jié)點(diǎn)每毫秒(同一機(jī)器,同一時(shí)間截)產(chǎn)生4096個(gè)ID序號(hào)<br>
 * 加起來(lái)剛好64位,為一個(gè)Long型。<br>
 * SnowFlake的優(yōu)點(diǎn)是,整體上按照時(shí)間自增排序,并且整個(gè)分布式系統(tǒng)內(nèi)不會(huì)產(chǎn)生ID碰撞(由數(shù)據(jù)中心ID和機(jī)器ID作區(qū)分),并且效率較高,經(jīng)測(cè)試,SnowFlake每秒能夠產(chǎn)生26萬(wàn)ID左右。
 *
 * @author Lucifer
 */
public class SnowFlake {
 
    // ==============================Fields===========================================
    /**
     * 開始時(shí)間截 (2018-07-03)
     */
 
    private final long twepoch = 1530607760000L;
 
    /**
     * 機(jī)器id所占的位數(shù)
     */
    private final long workerIdBits = 5L;
 
    /**
     * 數(shù)據(jù)標(biāo)識(shí)id所占的位數(shù)
     */
    private final long datacenterIdBits = 5L;
 
    /**
     * 支持的最大機(jī)器id,結(jié)果是31 (這個(gè)移位算法可以很快的計(jì)算出幾位二進(jìn)制數(shù)所能表示的最大十進(jìn)制數(shù))
     */
    private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
 
    /**
     * 支持的最大數(shù)據(jù)標(biāo)識(shí)id,結(jié)果是31
     */
    private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
 
    /**
     * 序列在id中占的位數(shù)
     */
    private final long sequenceBits = 12L;
 
    /**
     * 機(jī)器ID向左移12位
     */
    private final long workerIdShift = sequenceBits;
 
    /**
     * 數(shù)據(jù)標(biāo)識(shí)id向左移17位(12+5)
     */
    private final long datacenterIdShift = sequenceBits + workerIdBits;
 
    /**
     * 時(shí)間截向左移22位(5+5+12)
     */
    private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
 
    /**
     * 生成序列的掩碼,這里為4095 (0b111111111111=0xfff=4095)
     */
    private final long sequenceMask = -1L ^ (-1L << sequenceBits);
 
    /**
     * 工作機(jī)器ID(0~31)
     */
    private long workerId;
 
    /**
     * 數(shù)據(jù)中心ID(0~31)
     */
    private long datacenterId;
 
    /**
     * 毫秒內(nèi)序列(0~4095)
     */
    private long sequence = 0L;
 
    /**
     * 上次生成ID的時(shí)間截
     */
    private long lastTimestamp = -1L;
 
    //==============================Constructors=====================================
 
    /**
     * 構(gòu)造函數(shù)
     *
     * @param workerId     工作ID (0~31)
     * @param datacenterId 數(shù)據(jù)中心ID (0~31)
     */
    public SnowFlake(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==========================================
 
    /**
     * 獲得下一個(gè)ID (該方法是線程安全的)
     *
     * @return SnowflakeId
     */
    public synchronized long nextId() {
        long timestamp = timeGen();
 
        //如果當(dāng)前時(shí)間小于上一次ID生成的時(shí)間戳,說(shuō)明系統(tǒng)時(shí)鐘回退過(guò)這個(gè)時(shí)候應(yīng)當(dāng)拋出異常
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(
                    String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }
 
        //如果是同一時(shí)間生成的,則進(jìn)行毫秒內(nèi)序列
        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & sequenceMask;
            //毫秒內(nèi)序列溢出
            if (sequence == 0) {
                //阻塞到下一個(gè)毫秒,獲得新的時(shí)間戳
                timestamp = tilNextMillis(lastTimestamp);
            }
        }
        //時(shí)間戳改變,毫秒內(nèi)序列重置
        else {
            sequence = 0L;
        }
 
        //上次生成ID的時(shí)間截
        lastTimestamp = timestamp;
 
        //移位并通過(guò)或運(yùn)算拼到一起組成64位的ID
        return (((timestamp - twepoch) << timestampLeftShift)
                | (datacenterId << datacenterIdShift)
                | (workerId << workerIdShift)
                | sequence);
    }
 
    /**
     * 阻塞到下一個(gè)毫秒,直到獲得新的時(shí)間戳
     *
     * @param lastTimestamp 上次生成ID的時(shí)間截
     * @return 當(dāng)前時(shí)間戳
     */
    protected long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }
 
    /**
     * 返回以毫秒為單位的當(dāng)前時(shí)間
     *
     * @return 當(dāng)前時(shí)間(毫秒)
     */
    protected long timeGen() {
        return System.currentTimeMillis();
    }
 
    //==============================Test=============================================
 
    /**
     * 測(cè)試
     */
    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        SnowFlake idWorker = new SnowFlake(0, 0);
        Set set = new HashSet();
        for (int i = 0; i < 10000000; i++) {
            long id = idWorker.nextId();
            set.add(id);
            System.out.println("id----"+i+":"+id);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("set.size():" + set.size());
        System.out.println("endTime-startTime:" + (endTime - startTime));
    }
}

也可以在雪花算法生成的id的基礎(chǔ)上拼接日期,不過(guò)性能有所損耗。 

 public static String timestampConversionDate(String param) {
        Instant timestamp = Instant.ofEpochMilli(new Long(param));
        System.out.println("timestamp:"+param);
        LocalDateTime localDateTime = LocalDateTime.ofInstant(timestamp, ZoneId.systemDefault());
        String format = localDateTime.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        return format;
    }

測(cè)試1:

循環(huán)1000w次,發(fā)現(xiàn)并無(wú)重復(fù)

測(cè)試2:100個(gè)線程,每個(gè)線程負(fù)責(zé)生成10w個(gè)id

//多線程測(cè)試
public static void main(String[] args) throws InterruptedException {
        long startTime = System.currentTimeMillis();
        CountDownLatch countDownLatch=new CountDownLatch(10000000);
        final SnowFlake idWorker = new SnowFlake(0, 0);
        Set set = Collections.synchronizedSet(new HashSet());
        for (int i = 0; i < 100; i++) {
            Thread thread = new Thread(() -> {
                for (int i1 = 0; i1 < 100000; i1++) {
                    long id = idWorker.nextId();
                    System.out.println("id:"+id);
                    set.add(id);
                    countDownLatch.countDown();
                }
            });
            thread.start();
        }
        countDownLatch.await();
        long endTime = System.currentTimeMillis();
        System.out.println("set.size():" + set.size());
        System.out.println("endTime-startTime:" + (endTime - startTime));
    }

到此這篇關(guān)于Java生成訂單號(hào)或唯一id的高并發(fā)方案(4種方法)的文章就介紹到這了,更多相關(guān)Java生成訂單號(hào)或唯一id內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(51)

    Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(51)

    下面小編就為大家?guī)?lái)一篇Java基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧,希望可以幫到你
    2021-08-08
  • Springboot為什么加載不上application.yml的配置文件

    Springboot為什么加載不上application.yml的配置文件

    這篇文章主要介紹了Springboot為什么加載不上application.yml的配置文件,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • java IP地址網(wǎng)段計(jì)算的示例代碼

    java IP地址網(wǎng)段計(jì)算的示例代碼

    這篇文章主要介紹了java IP地址網(wǎng)段計(jì)算的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • java使用dbcp2數(shù)據(jù)庫(kù)連接池

    java使用dbcp2數(shù)據(jù)庫(kù)連接池

    這篇文章主要為大家詳細(xì)介紹了java使用dbcp2數(shù)據(jù)庫(kù)連接池的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • SpringMvc自動(dòng)裝箱及GET請(qǐng)求參數(shù)原理解析

    SpringMvc自動(dòng)裝箱及GET請(qǐng)求參數(shù)原理解析

    這篇文章主要介紹了SpringMvc自動(dòng)裝箱及GET請(qǐng)求參數(shù)原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • SpringBoot3集成swagger文檔的使用方法

    SpringBoot3集成swagger文檔的使用方法

    本文介紹了Swagger的誕生背景、主要功能以及如何在Spring Boot 3中集成Swagger文檔,Swagger可以幫助自動(dòng)生成API文檔,實(shí)現(xiàn)與代碼同步,并提供交互式測(cè)試功能,使用方法包括導(dǎo)入依賴、配置文檔、使用常見注解以及訪問(wèn)生成的Swagger UI和文檔,感興趣的朋友跟隨小編一起看看吧
    2025-01-01
  • Java基于swing實(shí)現(xiàn)的彈球游戲代碼

    Java基于swing實(shí)現(xiàn)的彈球游戲代碼

    這篇文章主要介紹了Java基于swing實(shí)現(xiàn)的彈球游戲代碼,包含了窗體界面設(shè)計(jì)與游戲的邏輯功能處理,具有不錯(cuò)的參考借鑒價(jià)值,需要的朋友可以參考下
    2014-11-11
  • Java判斷閏年的2種方法示例

    Java判斷閏年的2種方法示例

    這篇文章主要給大家介紹了關(guān)于Java判斷閏年的2種方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • Java深入講解static操作符

    Java深入講解static操作符

    static關(guān)鍵字基本概念我們可以一句話來(lái)概括:方便在沒(méi)有創(chuàng)建對(duì)象的情況下來(lái)進(jìn)行調(diào)用。也就是說(shuō):被static關(guān)鍵字修飾的不需要?jiǎng)?chuàng)建對(duì)象去調(diào)用,直接根據(jù)類名就可以去訪問(wèn),讓我們來(lái)了解一下你可能還不知道情況
    2022-07-07
  • Eclipse快捷鍵使用小結(jié)

    Eclipse快捷鍵使用小結(jié)

    Eclipse是用java的同行必不可少的工具,我總結(jié)了一下它的快捷鍵,太常用的ctrl+單擊、ctrl+shift+F、Ctrl+1等我就不細(xì)說(shuō)了,主要是方便查看。下邊小編就詳細(xì)的為大家介紹一下
    2013-07-07

最新評(píng)論