Java生成全局唯一的ID

10 篇文章 0 订阅
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

public class CodeCreator {
    public static final String PREFIX_REGEX = "[A-z]{1,3}";
    private static long workerId = 0;

    static {
        InetAddress address;
        try {
            address = InetAddress.getLocalHost();
        } catch (final UnknownHostException e) {
            throw new IllegalStateException("Cannot get LocalHost InetAddress, please check your network!");
        }
        byte[] ipAddressByteArray = address.getAddress();
        int i1 = ipAddressByteArray[1];
        int i2 = ipAddressByteArray[2];
        int i3 = ipAddressByteArray[3];
        i1 = i1 < 0 ? 256 + i1 : i1;
        i2 = i2 < 0 ? 256 + i2 : i2;
        i3 = i3 < 0 ? 256 + i3 : i3;
        // workerId = (long) ((((i1 << Byte.SIZE) + i2) << Byte.SIZE) + i3);
        workerId = (long) ((i2 << Byte.SIZE) + i3);
    }

    private static ReentrantLock instanceLock = new ReentrantLock();
    private static Map<String, CodeCreator> instances = new HashMap<>();

    private String prefix;
    private ReentrantLock lock = new ReentrantLock();
    private int number = 0;
    private int maxNumber = 10;
    private long lastTime = 0;

    /**
     * @param prefix 编码前缀;1-3个字符
     * @return
     */
    public static CodeCreator getInstance(String prefix) {
        return getInstance(prefix, 20);
    }

    /**
     * @param prefix 编码前缀;1-3个字符
     * @param len    编码总长度,最少20
     * @return
     */
    public static CodeCreator getInstance(String prefix, int len) {
        if (prefix == null || !prefix.matches(PREFIX_REGEX))
            throw new IllegalArgumentException("prefix must be 1 - 3 character");
        if (len - prefix.length() < 16 || len - prefix.length() > 25) {
            throw new IllegalArgumentException("length except prefix must between 16 and 25!");
        }

        String key = prefix + len;
        if (!instances.containsKey(key)) {
            instanceLock.lock();
            try {
                if (!instances.containsKey(key)) {
                    instances.put(key, new CodeCreator(prefix, len));
                }
            } finally {
                instanceLock.unlock();
            }
        }
        return instances.get(key);
    }

    private CodeCreator(String prefix, int len) {
        this.prefix = prefix;
        len = len - 10 - 5 - this.prefix.length();
        while (len-- > 1) {
            maxNumber = maxNumber * 10;
        }
    }

    public String next() {
        NextNumber nextNumber = getNextNumber();
        StringBuilder sb = new StringBuilder();
        sb.append(prefix).append(nextNumber.time);
        sb.append(String.valueOf(100000 + workerId).substring(1));
//        sb.append(prefix).append(nextNumber.time * 100000 + workerId);
        if (maxNumber >= 10) {
            long index = maxNumber + nextNumber.index;
            if (index >= 10)
                sb.append(String.valueOf(index).substring(1));
        }
        return sb.toString();
    }

    public long nextNumber() {
        NextNumber nextNumber = getNextNumber();
        if (nextNumber.time * 10000 + workerId > (Long.MAX_VALUE / maxNumber))
            throw new BusinessException("BIZ_UTIL", "根据你的设定,结果大于Long类型的上限,无法返回结果");
        return (nextNumber.time * 10000 + workerId) * maxNumber + nextNumber.index;
    }

    private NextNumber getNextNumber() {
        lock.lock();
        try {
            long time = System.currentTimeMillis() / 1000;
            if (lastTime != time) {
                lastTime = time;
                number = 0;
            } else {
                if (++number >= maxNumber) {
                    while (true) {
                        try {
                            Thread.sleep(10);
                        } catch (Exception e) {

                        }
                        time = System.currentTimeMillis() / 1000;
                        if (lastTime != time) {
                            lastTime = time;
                            number = 0;
                            break;
                        }
                    }
                }
            }
            NextNumber nextNumber = new NextNumber();
            nextNumber.time = time;
            nextNumber.index = number;
            return nextNumber;
        } finally {
            lock.unlock();
        }
    }

    class NextNumber {
        long time;
        long index;
    }
}

鸣谢:尚冠男

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值