首页 > 其他分享 >简易自增id生成器

简易自增id生成器

时间:2024-04-05 11:55:05浏览次数:30  
标签:自增 Seq seq 生成器 private public AtomicLong new id

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Function;

public class SeqManager {
    private final Seq seq;
    private final ExecutorService e = new ThreadPoolExecutor(1, 1,
            0L, TimeUnit.MILLISECONDS,
            new SynchronousQueue<>(), new ThreadPoolExecutor.DiscardPolicy());
    private final Function<Seq, Long> refreshSeqMax;

    public SeqManager(String key, Seq seq, Function<Seq, Long> refreshSeqMax, boolean load) {
        this.seq = seq;
        seq.key = key;
        this.refreshSeqMax = refreshSeqMax;
        if(load) {
            loadSeq();
        }
    }

    public long getSeq(long perWaitTime, TimeUnit tu) {
        long r = getSeq();
        while(r == -1) {
            try {
                tu.sleep(perWaitTime);
            } catch (InterruptedException ignored) {

            }
            r = getSeq();
        }
        return r;
    }

    public long getSeq() {
        //try load not load success will getSel() return -1;
        //not do block get, because may be effect response speed;
        loadSeq();
        long nextSeq = seq.trySeq.incrementAndGet();
        if(nextSeq > seq.maxSeq.get()) {
            seq.fullSeq.incrementAndGet();
            return -1;
        }
        return seq.nowSeq.incrementAndGet();
    }

    private void loadSeq() {
        // 大部分时间这里都会返回false
        if(seq.needLoad()) {
            //在并发的时候,只会提交成功一个。
            e.execute(() -> {
                //加锁进行seq加载,保证只会有一个线程在加载seq。
                synchronized (this) {
                    //二次检测seq是否需要加载,即使遇到刚加载完之后,但是线程感知延后,做了加载seq提交也能保证不会多次加载。
                    if (seq.needLoad()) {
                        long max = refreshSeqMax.apply(seq);
                        seq.maxSeq.addAndGet(max);
                        //获取超出来未获得的seq避免浪费seq。
                        long now = seq.fullSeq.get();
                        //还原Seq。
                        seq.trySeq.addAndGet(-now);
                        //清空被还原的数量。
                        seq.fullSeq.getAndAdd(-now);
                    }
                }
            });
        }
    }

    public static class Seq {
        private String key;
        private AtomicLong trySeq;//避免超消耗
        private AtomicLong fullSeq;//存储未被消耗的seq
        private AtomicLong nowSeq;//实际最新消耗的Seq
        private AtomicLong maxSeq;//当前加载的最大Seq
        private int loadNum;//剩下多少的时候加载
        private int step;//每次加载多少
        public Seq(AtomicLong trySeq, AtomicLong fullSeq, AtomicLong nowSeq, AtomicLong maxSeq, int loadNum, int step) {
            this.trySeq = trySeq;
            this.fullSeq = fullSeq;
            this.nowSeq = nowSeq;
            this.maxSeq = maxSeq;
            this.loadNum = loadNum;
            this.step = step;
        }

        public Seq(int loadNum, int step) {
            this.trySeq = new AtomicLong();
            this.fullSeq = new AtomicLong();
            this.nowSeq = new AtomicLong();
            this.maxSeq = new AtomicLong();
            this.loadNum = loadNum;
            this.step = step;
        }

        public boolean needLoad() {
            return nowSeq == null || maxSeq.get() - trySeq.get() <= loadNum;
        }

        public boolean full() {
            return maxSeq.get() - trySeq.get() < 0;
        }

        public String getKey() {
            return key;
        }

        public AtomicLong getTrySeq() {
            return trySeq;
        }

        public AtomicLong getFullSeq() {
            return fullSeq;
        }

        public AtomicLong getNowSeq() {
            return nowSeq;
        }

        public AtomicLong getMaxSeq() {
            return maxSeq;
        }

        public int getLoadNum() {
            return loadNum;
        }

        public int getStep() {
            return step;
        }
    }
}
import java.io.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

public class TestSeq {

    private static AtomicLong al = new AtomicLong(0);

    public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {
        SeqManager.Seq s = new SeqManager.Seq(1000, 100);
        SeqManager sm = new SeqManager("", s, a -> {
            return al.addAndGet(a.getStep());
        }, true);
        AtomicInteger ai = new AtomicInteger(0);
        ConcurrentSkipListMap<Long, Integer> clq = new ConcurrentSkipListMap<>();
        CompletableFuture<Void> [] cf = new CompletableFuture[10000];
        for(int i = 1;i <= 10000;i++) {
            int finalI = i;
            cf[i-1] = CompletableFuture.runAsync(() -> {
                long seq = sm.getSeq();
                if(seq == -1) {
                    ai.incrementAndGet();
                    return;
                }
                clq.put(seq, finalI);
            });
        }
        CompletableFuture.allOf(cf).get();
        new File("seq.txt").delete();
        try(FileWriter fw = new FileWriter("seq.txt")) {
            clq.forEach((k, v)->{
                try {
                    fw.write(k + ":" + v + "\n");
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        }
        System.out.println(ai.get());
    }

}

 

标签:自增,Seq,seq,生成器,private,public,AtomicLong,new,id
From: https://www.cnblogs.com/math-and-it/p/18115613

相关文章

  • RAID 5 搭建 挂载 更换
    目录分区添加5块硬盘使用lsblk查看磁盘情况使用fdisk进行分区创建RAID5mdadm命令查看RAID5状态创建文件系统建立挂载点并进行挂载将挂载写入开机启动项测试RAID5创建测试文件a.txt和b.txt模拟磁盘坏道维护RAID5分区添加5块硬盘使用lsblk查看磁盘情况......
  • Android 11.0 展讯平台长按power电源键开机时间修改
    1.前言在11.0的系统rom产品定制化开发中,在产品关机的情况下,长按power电源键的情况下,会开启机器然后进入开机流程中,否则就不会开机,但是为了防误撞,误开机要求延长长按power电源键开机时间,所以就需要从kernel中来分析下长按开机的相关源码来实现相关的功能2.展讯平台长按powe......
  • idea开发 java web 配电室后台管理系统bootstrap框架web结构java编程计算机网页
    一、源码特点 java配电室后台管理系统是一套完善的完整信息系统,结合javaweb开发和bootstrapUI框架完成本系统,对理解JSPjava编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。前段主要技术cssjquery bootstrapUI框架后端主要技术javaj......
  • Android pm命令
    在Android操作系统中,"pm"是PackageManager的缩写,它是一个用于管理安装、卸载和管理应用程序包的命令行工具。以下是一些常用的"pm"命令:1、列出所有安装的应用程序包:pmlistpackages 2、列出设备上的所有用户安装的应用程序包:pmlistpackages-3 3、列出设备......
  • 新增HIDL服务
    一、HIDL概述HIDL是用于指定HAL与其用户之间接口的一个接口描述语言,它允许将指定的类型与函数调用收集到接口和包中。更广泛地说,HIDL是一个可以让那些独立编译的代码库之间进行通信的系统。HIDL实际上是用于进行进程间通信的。进程间的通信可以称为Binder化。对于必须连......
  • 简单理解 React 的 createContext 和 Provider
    ......
  • vue axios sessionID 每次请求都不同的解决方式
    前端:        后端:注意:配置 allowedOrigins时,如果写的是http://localhost/,而请求的源地址是127.0.0.1。虽然它们通常指向同一台本地计算机,但在CORS规则中被视为不同的源。需更新更新allowedOrigins列表,将现有条目http://localhost:5174替换为http://127.......
  • Android操作sqlite数据库
    Sqlite数一种轻量级的关系型数据库,android里面可以用来持久化存储一些用户数据。一、SQLiteOpenHelper方式SQLiteOpenHelper是原生的数据库帮助类,继承这个类,用来创建,更新数据库的操作publicclassMySqliteOpenHelperextendsSQLiteOpenHelper{privatestaticfinal......
  • idea 安装了插件,显示已安装,实则没安装(重启后发现的)
    借用Plugininstalledbutnotavailable-Resolved看了上面的帖子,说是需要找到日志分析一下具体原因帖子里面安装了插件,实际上没安装是因为安装报错了,需要jdk1.6我安装jsonhelper这个插件一直没成功,是因为内存不足,更改了内存大小,重启安装即可。步骤打开"Helper"-......
  • idea异常:java.nio.charset.MalformedInputException: Input length = 1
    先放图吧,一般idea设置成这样都能解决写在后面:MalformedInputException是格式错误输入异常,意思就是指你的项目、配置文件编码不统一,所以我们要统一成UTF-8。一般小项目,肯定按照上图设置就没问题了,大项目文件多,特别是读属性这块,如果排查都没问题的话,可以重启项目,或者clean一下。......