使用AtomicInteger实现自增长编号

简介: 使用AtomicInteger实现自增长编号

有个需求,根据日期来生成一个自增长编号,格式:2019090400001。

思路是使用AtomicInteger原子操作类,好处就是不会出现重复,在多线程操作环境下优势尤为明显,可以自行研究一下。

下面是实现代码

public class TextUtil {
    public static ConcurrentHashMap<String, AtomicInteger> ID = new ConcurrentHashMap<>();
    private static String timeFlag;
    static {
        //初始值        
        ID.put("num", new AtomicInteger(1));
    }
    /**
     * 生成案件编号,格式:2019082300001
     * @return
     */
    public static String getCaseNo() {
        String now = DateUtil.getDate();
        if (!now.equals(timeFlag)) {
            timeFlag = now;
            ID.get("num").getAndSet(1);
        }
        int nextNum = ID.get("num").getAndIncrement();
        String str = String.format("%05d", nextNum);
        now += str;
        return now;
    }
    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            System.out.println(getCaseNo());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

测试结果

初步实现了功能,但是当项目重启后编号会重新开始计算。

这里考虑使用缓存机制把值存起来,项目重启时再次获取并赋值。

下面一个版本修改上述风险,使用文件存储,缺点就是增加了磁盘IO。

当然你可以使用更为高效的Redis或者其它技术。

public class TextUtil {
    public static ConcurrentHashMap<String, AtomicInteger> ID = new ConcurrentHashMap<>();
    private final static String file = TextUtil.class.getResource("").getPath() + "eventId.ini";
    private static String timeFlag;
    static {
        //初始值
        //程序启动时获取文件内容
        String str = read();
        int num = 1;
        if (StringUtils.isNotBlank(str)) {
            timeFlag = str.substring(0, 8);//最后更新日期,格式:yyyyMMdd
            String numStr = str.substring(8);
            num = Integer.parseInt(numStr);
            num++;
        }
        ID.put("num", new AtomicInteger(num));
    }
    /**
     * 生成编号,格式:2019082300001 
     *
     * @return
     */
    public static String getCaseNo() {
        String now = DateUtil.getDate();
        if (!now.equals(timeFlag)) {
            timeFlag = now;
            ID.get("num").getAndSet(1);
        }
        int nextNum = ID.get("num").getAndIncrement();
        store(nextNum + "");
        String str = String.format("%05d", nextNum);
        now += str;
        store(now);
        return now;
    }
    //存数据
    private static void store(String eventId) {
        //写入相应的文件
        BufferedOutputStream out = null;
        try {
            out = new BufferedOutputStream(new FileOutputStream(file));
            byte[] bytes = eventId.getBytes();
            //写入文件
            out.write(bytes, 0, bytes.length);
            //清缓存
            out.flush();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    //清缓存
                    out.flush();
                    out.close();
                } catch (Exception e) {
                }
            }
        }
    }
    //读数据
    private static String read() {
        String str = "";
        //读取文件(缓存字节流)
        BufferedInputStream in = null;
        try {
            File f = new File(file);
            if (!f.exists()) {
                f.createNewFile();
            }
            in = new BufferedInputStream(new FileInputStream(f));
            //读取数据
            //一次性取多少字节
            byte[] bytes = new byte[32];
            //接受读取的内容(n就代表的相关数据,只不过是数字的形式)
            int n = -1;
            //循环取出数据
            while ((n = in.read(bytes, 0, bytes.length)) != -1) {
                //转换成字符串
                str = new String(bytes, 0, n, "UTF-8");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭流
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return str;
    }
    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            System.out.println(getCaseNo());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

再次测试的时候就有连续性了

相关文章
|
6天前
主键自增
主键自增。
16 4
|
10月前
为什么要设置主键?
为什么要设置主键?
42 0
|
10月前
|
存储 关系型数据库 MySQL
InnoDB为什么使用自增id作为主键
InnoDB是MySQL数据库中一种常用的存储引擎,它使用自增id作为主键的设计是出于多方面的考虑。
281 0
|
11月前
|
SQL 关系型数据库 MySQL
列的完整性约束——设置表字段的非空约束(NOT NULL, NK)
列的完整性约束——设置表字段的非空约束(NOT NULL, NK)
|
SQL 关系型数据库 MySQL
Auto-increment 会在新记录插入表
Auto-increment 会在新记录插入表
77 0
|
存储 SQL 数据可视化
约束,MySQL约束,非空默认值,主键外键唯一自增,完整详细可收藏
约束,MySQL约束,非空默认值,主键外键唯一自增,完整详细可收藏
466 2
约束,MySQL约束,非空默认值,主键外键唯一自增,完整详细可收藏
|
SQL 开发者
主键自增长|学习笔记
快速学习主键自增长
|
存储 缓存 Oracle
关于自增id 你可能还不知道
在使用MySQL建表时,我们通常会创建一个自增字段(AUTO_INCREMENT),并以此字段作为主键。本篇文章将以问答的形式讲述关于自增id的一切。 注: 本文所讲的都是基于Innodb存储引擎。
224 0
|
存储 Java
关于自增操作,你真的懂了吗?
最近看见一道有意思的面试题,是关于自增操作的,让我回想起以前自己也遇到过,并且曾经也让我困惑过,今天拿出来跟大家分享,希望对大家有帮助。
166 0
关于自增操作,你真的懂了吗?