zoukankan      html  css  js  c++  java
  • 全局唯一的支付和订单id生成算法

    数据库存储的是两个Long类型的复合主键。显示到页面的是一个27位的数字单号

      1 package com.yunyihenkey.common.idworker;
      2 
      3 /**
      4  * 
      5  * @desc
      6  * @author jon snow
      7  * @version 1.0.0
      8  */
      9 public class SuperSnowflakeIdWorker {
     10 
     11     public static class NextId {
     12         private Long id1;
     13         private Long id2;
     14 
     15         public NextId(Long id1, Long id2) {
     16             this.id1 = id1;
     17             this.id2 = id2;
     18         }
     19 
     20         public Long getId1() {
     21             return id1;
     22         }
     23 
     24         public void setId1(Long id1) {
     25             this.id1 = id1;
     26         }
     27 
     28         public Long getId2() {
     29             return id2;
     30         }
     31 
     32         public void setId2(Long id2) {
     33             this.id2 = id2;
     34         }
     35 
     36     }
     37 
     38     /** 开始时间截(秒) */
     39     public static final long birth = 1498939440L;
     40 
     41     /** 机器id所占的位数 */
     42     public static final long workerIdBits = 20L;
     43 
     44     /** 序列在id中占的位数 */
     45     public static final long sequenceBits = 43L;
     46 
     47     /** 支持的最大机器id (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */
     48     public static final long maxWorkerId = -1L ^ (-1L << workerIdBits);
     49 
     50     /** 序列最大值 */
     51     public static final long sequenceMask = -1L ^ (-1L << sequenceBits);
     52 
     53     /** 工作机器ID(0~1048575 ) */
     54     private long workerId;
     55 
     56     /** 秒内序列(0~8796093022207) */
     57     private long sequence = 0L;
     58 
     59     /** 上次生成ID的时间截 */
     60     private long lastTimestamp = -1L;
     61 
     62     public SuperSnowflakeIdWorker(long workerId) {
     63         if (workerId > maxWorkerId || workerId < 0) {
     64             throw new IllegalArgumentException(
     65                     String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
     66         }
     67         this.workerId = workerId;
     68     }
     69 
     70     public synchronized NextId nextId() {
     71         long timestamp = timeGen();
     72 
     73         // 如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
     74         if (timestamp < lastTimestamp) {
     75             throw new RuntimeException(String.format(
     76                     "Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
     77         }
     78 
     79         // 如果是同一时间生成的,则进行秒内序列
     80         if (lastTimestamp == timestamp) {
     81             sequence = (sequence + 1) & sequenceMask;
     82             // 秒内序列溢出
     83             if (sequence == 0) {
     84                 // 阻塞到下一个秒,获得新的时间戳
     85                 timestamp = tilNextMillis(lastTimestamp);
     86             }
     87         }
     88         // 时间戳改变,秒内序列重置
     89         else {
     90             sequence = 0L;
     91         }
     92 
     93         // 上次生成ID的时间截
     94         lastTimestamp = timestamp;
     95 
     96         // 移位并通过或运算拼到一起组成64位的ID
     97         // long l = (workerId << sequenceBits) | sequence;
     98 
     99         // System.out.println(Long.toBinaryString(workerId) + ":+:" +
    100         // Long.toBinaryString(sequence));
    101         // String binaryString = Long.toBinaryString(l);
    102         // System.out.println("生成:" + zero.substring(0, 63 - binaryString.length()) +
    103         // binaryString);
    104         // System.out.println("生成数字:" + l + ":原始数字:"
    105         // + Long.valueOf(Long.toBinaryString(workerId) + Long.toBinaryString(sequence),
    106         // 2) + "end");
    107 
    108         // return new long[] { timestamp - birth, (workerId << sequenceBits) | sequence
    109         // };
    110         return new NextId(timestamp - birth, (workerId << sequenceBits) | sequence);
    111     }
    112 
    113     /**
    114      * 阻塞到下一个秒,直到获得新的时间戳
    115      * 
    116      * @param lastTimestamp
    117      *            上次生成ID的时间截
    118      * @return 当前时间戳
    119      */
    120     protected long tilNextMillis(long lastTimestamp) {
    121         long timestamp = timeGen();
    122         while (timestamp <= lastTimestamp) {
    123             timestamp = timeGen();
    124         }
    125         return timestamp;
    126     }
    127 
    128     private long timeGen() {
    129         return System.currentTimeMillis() / 1000;
    130     }
    131 
    132     /** 测试生成id */
    133     public static void main(String[] args) {
    134 
    135         SuperSnowflakeIdWorker idWorker = new SuperSnowflakeIdWorker(666);
    136         long currentTimeMillis = System.currentTimeMillis();
    137         int times = 100000000;
    138         for (int i = 0; i < times; i++) {
    139 
    140             // 获取一个复合主键id
    141             // NextId nextId = idWorker.nextId();
    142             idWorker.nextId();
    143 
    144             // System.out.println(Long.toBinaryString(id));
    145 
    146             // System.out.println("--------------------------------");
    147             // String zero =
    148             // "000000000000000000000000000000000000000000000000000000000000000";// 63个0
    149             // String binaryString = Long.toBinaryString(nextId.getId2());
    150             // BigInteger bigInteger = new BigInteger(
    151             // Long.toBinaryString(nextId.getId1()) + zero.substring(0, 63 -
    152             // binaryString.length()) + binaryString,
    153             // 2);
    154             // String string = bigInteger.toString();
    155             // System.out.println("数据库存储:id1=" + nextId.getId1() + "::id2=" +
    156             // nextId.getId2() + "::::页面显示订单号:" + string);
    157             // String string2 = bigInteger.toString(2);
    158             // System.out.println("id的比特字节::" + string2);
    159             //
    160             // int endIndex = string2.length() - 63;
    161             // System.out
    162             // .println("前端传过来的订单号:" + string + "" + " 解析-->id1=" +
    163             // Long.valueOf(string2.substring(0, endIndex), 2)
    164             // + "::id2=" + Long.valueOf(string2.substring(endIndex), 2));
    165         }
    166 
    167         long cost = System.currentTimeMillis() - currentTimeMillis;
    168         long l = times / (cost == 0 ? 1 : cost) * 1000;
    169         System.out.println("
    耗时(ms):" + cost + ",速度(万每秒):" + (l / 10000));
    170 
    171     }
    172 
    173     // /** 测试是否重复 */
    174     // public static final ConcurrentHashMap<Object, Object> map = new
    175     // ConcurrentHashMap<>(1000100);
    176     /** 测试是否重复 */
    177     // public static void main666(String[] args) {
    178     // // 9个线程
    179     // for (int i = 0; i < 9; i++) {
    180     // new Thread(new Runnable() {
    181     // @Override
    182     // public void run() {
    183     // MySnow idWorker = new MySnow(Thread.currentThread().getId());
    184     // for (int j = 0; j < 1000000; j++) {
    185     // NextId nextId = idWorker.nextId();
    186     // Object put = map.put(Long.toString(nextId.getId1()) +
    187     // Long.toString(nextId.getId2()), 1);
    188     // if (put != null) {
    189     // System.out.println("id重复!!!");
    190     // }
    191     // }
    192     // System.out.println(Thread.currentThread().getId() + ",线程跑完");
    193     // }
    194     // }).start();
    195     //
    196     // }
    197     //
    198     // }
    199 
    200 }
  • 相关阅读:
    Linux修改root密码报错
    Python中的排序---冒泡法
    Python随机数
    Python中的深拷贝和浅拷贝
    Couldn’t download https://raw.githubusercontent.com/certbot/certbot/ 问题解决
    Python内置数据结构----list
    Python内置数据结构
    Vue指令
    computed 和 watch
    Vue的数据响应式
  • 原文地址:https://www.cnblogs.com/wulm/p/9166022.html
Copyright © 2011-2022 走看看