1. 程式人生 > 實用技巧 >java三種生成ID演算法

java三種生成ID演算法

10000測試生成ID

RandomUtilIDWorkerNoCenter
第一次 0.187s 0.036s 0.324s
第二次 0.121s 0.05s 0.305s
第三次 0.131s 0.036s 0.283s

100000測試生成ID

RandomUtilIDWorkerNoCenter
第一次 0.678s 0.191s 0.922s
第二次 0.678s 0.201s 0.846s
第三次 0.684s 0.197s 0.932s

1000000測試生成ID

RandomUtilIDWorkerNoCenter
第一次 4.442s 1.933s 4.387s
第二次 4.316s 1.864s
4.571s
第三次 4.25s 1.782s 4.499s

10000000測試生成ID

RandomUtilIDWorkerNoCenter
第一次 37.291s 16.664s 37.096s
第二次 37.105s 16.583s 37.096s
第三次 37.44s 16.648s 37.096s

CODE

RandomUtil 
public class RandomUtil {

    private static String[] chars = new String[]{"a", "b", "c", "d", "e", "f",
            
"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
"W", "X", "Y", "Z"}; // private static String[] chars = new String[] { "0", "1", "2", "3", "4", "5", // "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", // "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", // "W", "X", "Y", "Z" }; public static String generateShortUuid() { StringBuffer shortBuffer = new StringBuffer(); String uuid = UUID.randomUUID().toString().replace("-", ""); for (int i = 0; i < 4; i++) { String str = uuid.substring(i * 4, i * 4 + 4); int x = Integer.parseInt(str, 16); shortBuffer.append(chars[x % 36]); } return String.valueOf(new RandomUtil(1, 2).nextId() + shortBuffer.toString()); } /** * 起始的時間戳 */ private final static long START_STMP = 1420041600000L; /** * 序列號佔用的位數 */ private final static long SEQUENCE_BIT = 12L; /** * 機器標識佔用的位數 */ private final static long MACHINE_BIT = 5L; /** * 資料中心佔用的位數 */ private final static long DATACENTER_BIT = 5L; /** * 每一部分的最大值 */ private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT); private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT); private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT); /** * 每一部分向左的位移 */ private final static long MACHINE_LEFT = SEQUENCE_BIT; private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT; private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT; /** * 資料中心 */ private long datacenterId; /** * 機器標識 */ private long machineId; /** * 序列號 */ private long sequence = 0L; /** * 上一次時間戳 */ private long lastStmp = -1L; public RandomUtil(long datacenterId, long machineId) { if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) { throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0"); } if (machineId > MAX_MACHINE_NUM || machineId < 0) { throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0"); } this.datacenterId = datacenterId; this.machineId = machineId; } /** * 產生下一個ID * * @return */ public synchronized long nextId() { long currStmp = getNewstmp(); if (currStmp < lastStmp) { throw new RuntimeException("Clock moved backwards. Refusing to generate userId"); } if (currStmp == lastStmp) { //相同毫秒內,序列號自增 sequence = (sequence + 1) & MAX_SEQUENCE; //同一毫秒的序列數已經達到最大 if (sequence == 0L) { currStmp = getNextMill(); } } else { //不同毫秒內,序列號置為0 sequence = 0L; } lastStmp = currStmp; //時間戳部分 return (currStmp - START_STMP) << TIMESTMP_LEFT //資料中心部分 | datacenterId << DATACENTER_LEFT //機器標識部分 | machineId << MACHINE_LEFT //序列號部分 | sequence; } private long getNextMill() { long mill = getNewstmp(); while (mill <= lastStmp) { mill = getNewstmp(); } return mill; } private long getNewstmp() { return System.currentTimeMillis(); } public static void main(String[] args) { long startTime = System.currentTimeMillis(); for (int i = 0; i < 10000000; i++) { System.out.println(RandomUtil.generateShortUuid()); } long endTime = System.currentTimeMillis(); float excTime = (float) (endTime - startTime) / 1000; System.out.println("執行時間:" + excTime + "s"); } }
View Code

IDWorker
public class IDWorker {

    /**
     * 起始的時間戳
     */
    private final static long START_STMP = 1480166465631L;

    /**
     * 每一部分佔用的位數
     */
    private final static long SEQUENCE_BIT = 12; //序列號佔用的位數
    private final static long MACHINE_BIT = 5;   //機器標識佔用的位數
    private final static long DATACENTER_BIT = 5;//資料中心佔用的位數

    /**
     * 每一部分的最大值
     */
    private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);
    private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
    private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);

    /**
     * 每一部分向左的位移
     */
    private final static long MACHINE_LEFT = SEQUENCE_BIT;
    private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
    private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;

    private long datacenterId;  //資料中心
    private long machineId;     //機器標識
    private long sequence = 0L; //序列號
    private long lastStmp = -1L;//上一次時間戳

    public IDWorker(long datacenterId, long machineId) {
        if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
            throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");
        }
        if (machineId > MAX_MACHINE_NUM || machineId < 0) {
            throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
        }
        this.datacenterId = datacenterId;
        this.machineId = machineId;
    }

    /**
     * 產生下一個ID
     *
     * @return
     */
    public synchronized long nextId() {
        long currStmp = getNewstmp();
        if (currStmp < lastStmp) {
            throw new RuntimeException("Clock moved backwards.  Refusing to generate id");
        }

        if (currStmp == lastStmp) {
            //相同毫秒內,序列號自增
            sequence = (sequence + 1) & MAX_SEQUENCE;
            //同一毫秒的序列數已經達到最大
            if (sequence == 0L) {
                currStmp = getNextMill();
            }
        } else {
            //不同毫秒內,序列號置為0
            sequence = 0L;
        }

        lastStmp = currStmp;

        return (currStmp - START_STMP) << TIMESTMP_LEFT //時間戳部分
                | datacenterId << DATACENTER_LEFT       //資料中心部分
                | machineId << MACHINE_LEFT             //機器標識部分
                | sequence;                             //序列號部分
    }

    private long getNextMill() {
        long mill = getNewstmp();
        while (mill <= lastStmp) {
            mill = getNewstmp();
        }
        return mill;
    }

    private long getNewstmp() {
        return System.currentTimeMillis();
    }

    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        IDWorker idWorker = new IDWorker(2, 3);
        for (int i = 0; i < 10000000; i++) {
            System.out.println(idWorker.nextId());
        }
        long endTime = System.currentTimeMillis();
        float excTime = (float) (endTime - startTime) / 1000;
        System.out.println("執行時間:" + excTime + "s");
    }

}
View Code

OrderNoCenter
public class OrderNoCenter {

    private Logger logger = LoggerFactory.getLogger(OrderNoCenter.class);

    private static final String WORKERID_PATH = "/etc/workerId";

    private OrderNoCenter() {
    }

    private static class OrderNoCenterHolder {
        private static OrderNoCenter instance = new OrderNoCenter();
    }

    public static OrderNoCenter getInstance() {
        return OrderNoCenterHolder.instance;
    }

    /**
     * 節點 ID 預設取1
     */
    private long workerId = 1;
    /**
     * 序列id 預設取1
     */
    private long sequence = 1;

    /**
     * 機器標識位數
     */
    private final long workerIdBits = 10L;
    /**
     * 機器ID最大值
     * 結果就是2的workerBits次方-1,能表示的最大數.全部1亦或10位0,就是0開頭最後10位1
     */
    private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
    /**
     * 毫秒內自增位
     */
    private final long sequenceBits = 12L;
    /**
     * 機器ID偏左移12位
     */
    private final long workerIdShift = sequenceBits;
    /**
     * 資料中心ID左移17位
     */
    private final long datacenterIdShift = sequenceBits + workerIdBits;

    private final long sequenceMask = -1L ^ (-1L << sequenceBits);

    /**
     * 時間毫秒左移22位
     */
    private final long timestampLeftShift = sequenceBits + workerIdBits;

    private long lastTimestamp = -1L;

    public void initParam() {
        // 從預設位置讀取workerId,最大1024
        try {
            File conf = new File(WORKERID_PATH);
            if (conf.exists()) {
                //這裡引入common io或者直接自己寫讀取檔案
                String str = FileUtils.readFileToString(conf);
                workerId = Integer.parseInt(str);
            } else {
                logger.warn(" worker id not found,will use default value...");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        logger.info(" worker id is {}", workerId);
        if (workerId < 0 || workerId > maxWorkerId) {
            throw new IllegalArgumentException("workerId is illegal: "
                    + workerId);
        }
    }

    public long getWorkerId() {
        return workerId;
    }

    public long getTime() {
        return System.currentTimeMillis();
    }

    public String create() {
        return nextNo();
    }

    /**
     * 獲取id 執行緒安全
     *
     * @return
     */
    private synchronized String nextNo() {
        long timestamp = timeGen();
        // 時間錯誤
        if (timestamp < lastTimestamp) {
            throw new IllegalStateException("Clock moved backwards.");
        }
        // 當前毫秒內,則+1
        if (lastTimestamp == timestamp) {
            // 當前毫秒內計數滿了,則等待下一秒
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0;
        }
        lastTimestamp = timestamp;
        // ID偏移組合生成最終的ID,並返回ID,最大十位數

        long id = ((timestamp % 1000) << timestampLeftShift) | (workerId << workerIdShift) | sequence;
        //建議使用common lang format
        //報錯的話,可以替換為

        String timestampStr = new SimpleDateFormat("yyyyMMddHHmmss").format(timestamp);

        return timestampStr + String.format("%010d", id);
    }

    /**
     * 等待下一個毫秒的到來
     *
     * @param lastTimestamp
     * @return
     */
    private long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    private long timeGen() {
        return System.currentTimeMillis();
    }

    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i++) {
            System.out.println(OrderNoCenter.getInstance().create());
        }
        long endTime = System.currentTimeMillis();
        float excTime = (float) (endTime - startTime) / 1000;
        System.out.println("執行時間:" + excTime + "s");
    }


}
View Code

生成演算法是從網上找的,非本人純手擼!
在此感謝