订单号唯一ID顺序生成(一个轻量的实现)

一个唯一的ID可以使用UUID,但不是顺序的。

一个自增的ID可以使用数据库序列、自增主键、雪花算法等等。

本文分享一个简单实用的一个ID生成代码,支持生成顺序自增且唯一的ID,一个工具类可以直接拷贝使用,简单、轻量。

原理:

        ID组成规则: yyyyMMddHHmmssSSS + 自定义的位数(每秒并发数量)

        生成逻辑:每毫秒时间戳开始加自定义的位数如4位 20220526111200000+0000,如果该时间内已经生成过该ID,那么自定义的位数自增1(20220526111200000+0001),即可认为每毫秒支持生成自定义位数的唯一ID(每毫秒多少并发)

代码如下:

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class UniqueSeqUtil {
	private static volatile int seq = 0;
	private static volatile long currentTimeMillis;

	public static class UniqueId {
		private final long currentTimeMillis;
		private final String id;
		private final String compensate;

		public UniqueId(long currentTimeMillis, String id, String compensate) {
			this.currentTimeMillis = currentTimeMillis;
			this.id = id;
			this.compensate = compensate;
		}

		/**
		 * 生成该id时候的时间戳
		 */
		public long getCurrentTimeMillis() {
			return currentTimeMillis;
		}

		/**
		 * 唯一ID
		 */
		public String getId() {
			return id;
		}

		/**
		 * 补全的位,该时间戳的第几个
		 */
		public String getCompensate() {
			return compensate;
		}
	}

	/**
	 * 生成一个唯一的订单序列,长度为 yyyyMMddHHmmssSSS + compensateI
	 * 
	 * @param compensateI 4 代表长度加4位 ,支持每毫秒4位的并发
	 * @return
	 */
	public final static synchronized UniqueId uniqueId(int compensateI) {
		final long ctm = System.currentTimeMillis();
		if (currentTimeMillis != ctm) {
			seq = 0;
			currentTimeMillis = ctm;
		}
		String compensate = "";// 补零
		String sqlStr = String.valueOf(++seq);
		int length = sqlStr.length();
		for (int i = 0; i < compensateI - length; i++) {
			compensate += "0";
		}
		String currentTimeStr = (new SimpleDateFormat("yyyyMMddHHmmssSSS")).format(new Date(ctm));
		String id = currentTimeStr + compensate + sqlStr;
		return new UniqueId(ctm, id, compensate);
	}

	
	private static volatile long currentTimeMillis1;
	/**
	 * 生成一个唯一序列yyyyMMddHHmmssSSS,延迟一毫秒生成,多线程调用那么串行
	 */
	public static String yyyyMMddHHmmssSSS() {
		long ctm;
		synchronized (UniqueSeqUtil.class) {
			while (true) {
				ctm = System.currentTimeMillis();
				if (currentTimeMillis1 != ctm) {
					currentTimeMillis1 = ctm;
					break;
				}
			}
		}
		String currentTimeStr = (new SimpleDateFormat("yyyyMMddHHmmssSSS")).format(new Date(ctm));
		return currentTimeStr;
	}
	
}

测试该工具类生成ID是否安全,使用一个线程安全的Map去记录生成的ID,如果发现重复的ID那么就抛出异常

代码如下 :

public static void main(String[] args) {
		final Map<String,Integer> aa=new ConcurrentHashMap<String, Integer>();
		for (int i = 0; i < 50; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					while (true) {
						String key = uniqueId(4).getId();
						if(aa.containsKey(key)) {
							throw new RuntimeException("重复");
						}else {
							aa.put(key, 1);
							System.out.println(key+"\t"+aa.size());
						}
					}
				}
			}).start();
		}

	}

 

执行结果:

 

测试发现生成速度还是很快的(具体读者可以自己测试,感觉一秒可以生成上万个ID),下图可以验证说明程序生成的ID是不会重复的(程序可靠)

 总结:当然以上的程序性能并非是最优的,读者可以优化,若加上服务器ID号,就可以用来做分布式ID生成器,

如:ID规则 = 服务器ID + yyyyMMddHHmmssSSS + 自定义的位数(每秒并发数量)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

邓霖涛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值