废话不多说系列,直接上代码
(1)完整源码
package edu.study.module.up.util.common;
import java.net.InetAddress;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
/**
* 唯一订单号ID 生成工具类
*/
public class IDUtils {
/**
* 最近的时间戳
*/
private long lastTimestamp = 0;
/**
* 机器id 2位
*/
private final String machineId;
/**
* 0,并发控制
*/
private long sequence = 0L;
/**
* 机器IP <br/>
* 注意:分布式环境,注意每台机器的id要保证不同;也可以使用机器ip,映射成一个数字编号(如01:192.168.55.12)
*/
private static String myid = "";
{
try {
String address = InetAddress.getLocalHost().getHostAddress();
System.out.println("当前主机ID地址:" + address);
if (this.isBlank(address)) {
int v = (int) (Math.random() * 10000);
myid = v + "";
} else {
myid = address;
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 单例-双重检验锁
*/
private volatile static IDUtils instance = null;
public static IDUtils getInstance() {
if (instance == null) {
synchronized (IDUtils.class) {
if (instance == null) {
instance = new IDUtils(myid);
}
}
}
return instance;
}
public IDUtils(String machineId) {
this.machineId = machineId;
}
/**
* 补码 (补齐固定长度的位数)
*/
private String leftPad(long i, int n) {
String s = String.valueOf(i);
StringBuilder sb = new StringBuilder();
int c = n - s.length();
c = Math.max(c, 0);
for (int t = 0; t < c; t++) {
sb.append("0");
}
return sb.append(s).toString();
}
/**
* 等待下一个毫秒的到来, 保证返回的毫秒数在参数lastTimestamp之后
*/
private long tilNextMillis(long lastTimestamp) {
long timestamp = System.currentTimeMillis();
while (timestamp <= lastTimestamp) {
timestamp = System.currentTimeMillis();
}
return timestamp;
}
/**
* 字符串为null或空字符串序列
*
* @param cs 字符串非空
* @return true 空
*/
private boolean isBlank(CharSequence cs) {
int strLen = cs == null ? 0 : cs.length();
if (strLen != 0) {
for (int i = 0; i < strLen; ++i) {
if (!Character.isWhitespace(cs.charAt(i))) {
return false;
}
}
}
return true;
}
/**
* 获取订单号
*/
public String getOrderNumber() {
return IDUtils.getInstance().nextId();
}
/**
* 生成订单号
*/
public synchronized String nextId() {
// JDK1.8+
LocalDateTime now = LocalDateTime.now();
String time = now.format(DateTimeFormatter.ofPattern("yyMMddHHmmssSSS", Locale.ROOT));
// 时区设置(东八区-北京)
long timestamp = now.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
if (this.lastTimestamp == timestamp) {
// 如果上一个timestamp与新产生的相等,则sequence加一(0-4095循环);
// 对新的timestamp,sequence从0开始
// 序列号的最大值
int sequenceMax = 9999;
this.sequence = this.sequence + 1 % sequenceMax;
if (this.sequence == 0) {
// 重新生成timestamp
timestamp = this.tilNextMillis(this.lastTimestamp);
}
} else {
this.sequence = 0;
}
this.lastTimestamp = timestamp;
return time + machineId + leftPad(sequence, 4);
}
/**
* 调用示范
*/
public static void main(String[] args) {
// 测试:并发验证是否唯一
//for (int i = 0; i < 10000; i++) {
// new Thread(() -> System.out.println(IDUtils.getInstance().getOrderNumber())).start();
//}
System.out.println("获取订单号-19位[方式一]:" + IDUtils.getInstance().nextId());
System.out.println("获取订单号-19位[方式二]:" + IDUtils.getInstance().getOrderNumber());
}
}
(2)测试结果
当前主机ID地址:192.168.174.1
获取订单号-19位[方式一]:2204281132447530000
获取订单号-19位[方式二]:2204281132447640000