【Java 开发实例】Java 唯一订单号ID生成示范

100 阅读2分钟

废话不多说系列,直接上代码

(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