" />

亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

java如何根據(jù)時(shí)間戳生成有序ID

 更新時(shí)間:2024年04月15日 10:01:57   作者:紫金丨小飛俠  
這篇文章主要介紹了java如何根據(jù)時(shí)間戳生成有序ID問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

引言

我們常用的主鍵有這么幾種

1. 數(shù)據(jù)庫自增主鍵,比如mysql的autoincrement,這種插入快,但是識(shí)別度不高

2. uuid 這個(gè)號(hào)稱是全球唯一的,但是無序,沒有實(shí)際意義,只能保證唯一

3. 時(shí)間戳,這種在分布式的場(chǎng)景下就需要考慮更多種情況

4. 雪花算法 snow flake ,分布式全局唯一主鍵,很牛,但是我覺得用起來也挺麻煩哈哈哈

所以在并發(fā)情況沒那么大的時(shí)候用一個(gè)工具類搞定,我就是這么懶

工具類

@Slf4j
public class NumUtil {

    private static long tmpID = 0;
    private static final long LOCK_TIME = 1;
    private static final long INCREASE_STEP = 1;
    private static SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmssSSS");
    private static final Lock LOCK = new ReentrantLock();


    public static long nextPkId() throws InterruptedException {
        //當(dāng)前:(年、月、日、時(shí)、分、秒、毫秒)
        long timeCount;
        if (LOCK.tryLock(LOCK_TIME, TimeUnit.SECONDS)) {
            timeCount = Long.parseLong(sdf.format(new Date()));
            try {
                if (tmpID < timeCount) {
                    tmpID = timeCount;
                } else {
                    tmpID += INCREASE_STEP;
                    timeCount = tmpID;
                }
                return timeCount;
            } finally {
                LOCK.unlock();
            }
        } else {
            log.error("lock failed");
            return nextPkId();

        }
    }
}

貼上代碼,這里用了當(dāng)前時(shí)間,精確到毫秒級(jí),如果有需要的話可以在實(shí)例化timeCount的時(shí)候乘以10或者100 1000之類的,這個(gè)看大家,然后加上鎖,防止線程不安全的情況,加鎖失敗的時(shí)候遞歸,再來一次。

也可以使用synchronized做成同步方法,當(dāng)中的區(qū)別下次再討論。

有評(píng)論說宕機(jī)會(huì)導(dǎo)致tmpID歸0導(dǎo)致已經(jīng)使用過超出當(dāng)前時(shí)間的ID,所以持久化這個(gè)tmpID也是可以的。

但這也就是在并發(fā)沒那么高的情況下才使用這種方法,一般并發(fā)場(chǎng)景下還是分布式鎖+推特的雪花算法解決。

測(cè)試

public static void numTest() {
        ExecutorService executorService = Executors.newCachedThreadPool();
        int n = 10000;
        List<Long> list = new ArrayList<>();
        CountDownLatch latch = new CountDownLatch(n);
        for (int i = 0; i < n; i++) {
            executorService.execute(() -> {
                //執(zhí)行業(yè)務(wù)請(qǐng)求
                try {
                    list.add(NumUtil.nextPkId());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                latch.countDown();
            });
        }
        try {
            // 一定記得加上timeout時(shí)間,防止阻塞主線程
            latch.await(3000, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            log.error(e.getMessage());
        }
        //4.等待所有子任務(wù)完成,組裝內(nèi)容
        while (list.size() < n) {
            log.info("集合長度 >>> {}",list.size());
        }
        //5.關(guān)閉線程池
        executorService.shutdown();

        for (Long aLong : list) {
            System.out.println(aLong);
        }
    }

然后噼里啪啦打印了一萬個(gè)ID,沒有重復(fù)的,一秒以內(nèi)生成

結(jié)論

當(dāng)然這種只是為了單體或者是并發(fā)沒有高到那么離譜的場(chǎng)景下使用,效率我覺得還不錯(cuò),分布式的場(chǎng)景下可能需要用到redis的自增來計(jì)數(shù)以達(dá)到數(shù)據(jù)安全的效果

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家

相關(guān)文章

  • SpringBoot使用itext填充pdf表單及導(dǎo)出pdf的流程

    SpringBoot使用itext填充pdf表單及導(dǎo)出pdf的流程

    由于最近開發(fā)的項(xiàng)目需要用到打印單據(jù),就在網(wǎng)上找了一下方案,反反復(fù)復(fù),都沒有找到合適的,借鑒了網(wǎng)上資源,使用itext5、itext7的工具包,所以本文介紹了SpringBoot使用itext填充pdf表單及導(dǎo)出pdf的流程,需要的朋友可以參考下
    2024-09-09
  • Java分布式session存儲(chǔ)解決方案圖解

    Java分布式session存儲(chǔ)解決方案圖解

    這篇文章主要介紹了Java分布式session存儲(chǔ)解決方案圖解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • 詳解java定時(shí)任務(wù)

    詳解java定時(shí)任務(wù)

    這篇文章主要為大家詳細(xì)介紹了java定時(shí)任務(wù),使用JDK中的Timer定時(shí)任務(wù)來實(shí)現(xiàn),感興趣的小伙伴們可以參考一下
    2016-03-03
  • Java多線程案例實(shí)戰(zhàn)之定時(shí)器的實(shí)現(xiàn)

    Java多線程案例實(shí)戰(zhàn)之定時(shí)器的實(shí)現(xiàn)

    在Java中可以使用多線程和定時(shí)器來實(shí)現(xiàn)定時(shí)任務(wù),下面這篇文章主要給大家介紹了關(guān)于Java多線程案例之定時(shí)器實(shí)現(xiàn)的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-01-01
  • Java預(yù)防SQL注入的具體實(shí)踐方法

    Java預(yù)防SQL注入的具體實(shí)踐方法

    在?Java?中預(yù)防?SQL?注入的核心是?避免直接拼接?SQL?語句,并通過參數(shù)化查詢、ORM?框架和嚴(yán)格的輸入驗(yàn)證來實(shí)現(xiàn)安全防護(hù),以下是具體實(shí)踐方法,感興趣的小伙伴跟著小編一起來看看吧
    2025-01-01
  • 將InputStream轉(zhuǎn)化為base64的實(shí)例

    將InputStream轉(zhuǎn)化為base64的實(shí)例

    這篇文章主要介紹了將InputStream轉(zhuǎn)化為base64的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • SpringBoot啟動(dòng)失敗的原因及其解決方法

    SpringBoot啟動(dòng)失敗的原因及其解決方法

    對(duì)于springboot的啟動(dòng)失敗,相信大家都有經(jīng)歷,但是為什么會(huì)啟動(dòng)失敗,以及怎么解決都只能通過日志進(jìn)行查看,在這里,我會(huì)將常見的springboot啟動(dòng)失敗的報(bào)錯(cuò)一一展示,需要的朋友可以參考下
    2024-06-06
  • Java設(shè)計(jì)模式之觀察者模式(Observer模式)介紹

    Java設(shè)計(jì)模式之觀察者模式(Observer模式)介紹

    這篇文章主要介紹了Java設(shè)計(jì)模式之觀察者模式(Observer模式)介紹,Java深入到一定程度,就不可避免的碰到設(shè)計(jì)模式(design pattern)這一概念,了解設(shè)計(jì)模式,將使自己對(duì)java中的接口或抽象類應(yīng)用有更深的理解,需要的朋友可以參考下
    2015-03-03
  • Springboot+redis+Interceptor+自定義annotation實(shí)現(xiàn)接口自動(dòng)冪等

    Springboot+redis+Interceptor+自定義annotation實(shí)現(xiàn)接口自動(dòng)冪等

    本篇文章給大家介紹了使用springboot和攔截器、redis來優(yōu)雅的實(shí)現(xiàn)接口冪等,對(duì)于冪等在實(shí)際的開發(fā)過程中是十分重要的,因?yàn)橐粋€(gè)接口可能會(huì)被無數(shù)的客戶端調(diào)用,如何保證其不影響后臺(tái)的業(yè)務(wù)處理,如何保證其只影響數(shù)據(jù)一次是非常重要的,感興趣的朋友跟隨小編一起看看吧
    2019-07-07
  • 詳解如何使用MyBatis簡化JDBC開發(fā)

    詳解如何使用MyBatis簡化JDBC開發(fā)

    JavaEE?企業(yè)級(jí)?Java?項(xiàng)目中的經(jīng)典三層架構(gòu)為表現(xiàn)層,業(yè)務(wù)層和持久層.MyBatis?對(duì)?JDBC?代碼進(jìn)行了封裝,作為一款優(yōu)秀的持久層框架,專門用于簡化JDBC開發(fā).本文主要介紹一下如何使用MyBatis簡化JDBC開發(fā),需要的可以參考一下
    2023-01-01

最新評(píng)論