• 参考snowflake算法,基本思路:
  • 序列12位(更格式化的输出后,性能损耗导致每毫秒生成不了这么多,所以可以考虑减少这里的位,不过留着也并无影响)

  • 机器位10位

  • 毫秒为左移 22位

  • 上述几个做或运算后得出一个唯一的数,转10进制后,最大10位,最小7位,string.format来统一为10,format性能影响,导致性能降低3倍左右

FilUtils不想用的话,1太机器可以直接考虑使用1,多机器根据代码配置id

代码如下:

package net.gitosc.lianqu1990.utils.code;

import net.gitosc.lianqu1990.utils.date.DateFormatUtils;
import net.gitosc.lianqu1990.utils.date.TimeMark;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.io.File; /**
* 缺陷是,订单量没那么大,导致机器码|序列 后,一般都是4096
* 通过将毫秒引入序列后修正
* 后来加了format以后性能受损,比idcenter慢10倍,每秒可以生成50w,idcenter将近500w,不过这也是idcenter极限
* 够用,暂不优化
* @author hanchao
* @date 2017/4/20 19:01
*/
public class OrderNoCenter { public static final 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最大值
*/
private final long maxWorkerId = -1L ^ (-1L << workerIdBits); //结果就是2的workerBits次方-1,能表示的最大数.全部1亦或10位0,就是0开头最后10位1
/**
* 毫秒内自增位
*/
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()){
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;
String timestampStr = DateFormatUtils.NUMBER_FORMAT.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();
} /**
* 最大十位,最小7位,补0format
*/
/*public void test(){
String t = String.valueOf((1L << 22) | (1 << 12) | 0);
String t1 = String.valueOf((999L << 22) | (1023 << 12) | 0);
System.out.println(DateFormatUtils.NUMBER_FORMAT.format(System.currentTimeMillis())+"-"+t);
System.out.println(DateFormatUtils.NUMBER_FORMAT.format(System.currentTimeMillis())+"-"+t1);
long l1 = (1L << 22) | (1 << 12) | 0;
long l2 = (999L << 22) | (1023 << 12) | 0;
System.out.println(l1);
System.out.println(l2);
System.out.println(String.format("%010d",l1));
System.out.println(String.format("%010d",l2));
}*/ public static void main(String[] args){
for (int i = 0; i < 100; i++) {
System.out.println(OrderNoCenter.getInstance().create());
} //性能测试
TimeMark mark = new TimeMark();
for (int i = 0; i < 1000000; i++) {
OrderNoCenter.getInstance().create();
}
mark.simplePrint(); mark.mark(); for (int i = 0; i < 1000000; i++) {
IdCenter.getInstance().getId();
}
mark.simplePrint();
}
}

缺少代码的话,请直接使用我的附件代码

附件:

代码代码代码代码代码点击下载下载

业务订单号生成算法,每秒50W左右,不同机器保证不重复,包含日期可读性好的更多相关文章

  1. 订单号生成逻辑,C#和JAVA双版

    五年没写过博客了,倒是天天在看 转来转去,又转回技术 原来一直在使用微软爸爸的东西,最近一两年开始玩android,玩java,还有PostgreSQL 都有些应用了,倒是可以整理些随笔出来,这就是其 ...

  2. Java订单号生成,唯一订单号(日均千万级别不重复)

    Java订单号生成,唯一订单号 相信大家都可以搜索到很多的订单的生成方式,不懂的直接百度.. 1.订单号需要具备以下几个特点. 1.1 全站唯一性. 1.2 最好可读性. 1.3 随机性,不能重复,同 ...

  3. 偶尔在网上看到的,相对比较好的c#端订单号生成规则

    偶尔在网上看到的,相对比较好的c#端订单号生成规则 public class BillNumberBuilder{     private static object locker = new obj ...

  4. 全局唯一订单号生成方法(参考snowflake)

    backgroud Snowflake is a network service for generating unique ID numbers at high scale with some si ...

  5. 全局唯一的支付和订单id生成算法

    数据库存储的是两个Long类型的复合主键.显示到页面的是一个27位的数字单号 package com.yunyihenkey.common.idworker; /** * * @desc * @aut ...

  6. 基于redis的订单号生成方案

    目前,比较火的nosql数据库,如MongoDB,Redis,Riak都提供了类似incr原子行操作. 下面是PHP版的一种实现方式: <?php /** * 基于Redis的全局订单号id * ...

  7. C#端一个不错的订单号生成规则

    /// <summary> /// 订单助手 /// </summary> public class OrderHelper { /// <summary> /// ...

  8. EMS快递单号生成算法

    <?php function emsnum($ems, $num) { $fri = substr($ems, 2, 8); $head = substr($ems, 0, 2); $tail ...

  9. MSSQL高并发下生成连续不重复的订单号

    一.确定需求 只要做过开发的基本上都有做过订单,只要做过订单的基本上都要涉及生成订单号,可能项目订单号生成规则都不一样,但是大多数规则都是连续增长. 所以假如给你一个这样的需求,在高并发下,以天为单位 ...

随机推荐

  1. 香港多IP站群服务器-搭建多IP代理服务器、游戏加速服务器

    耀磊花楹qq82521463香港WK自营机房多IP服务器租用,多IP站群服务器,多IP多C段 站群服务器租用 耀磊数据拥有3万个自由香港IP以及独立AS号,是APNIC核心成员,机房通过BGP融合 多 ...

  2. 1054: [HAOI2008]移动玩具

    1054: [HAOI2008]移动玩具 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1272  Solved: 690[Submit][Statu ...

  3. Hibernate注解之@Enumerated

    Hibernate注解之@Enumerated 转:http://www.cnblogs.com/minideas/archive/2011/11/04/2235262.html @Enumerate ...

  4. FDG内存分配器笔记

    FDG: 大规模并行系统中的动态内存分配器由于需要全局同步(记账) ,导致性能急剧下降. 代码解析 1.superblock 类中包含两个变量,两个函数.默认superblock大小为2048 ite ...

  5. java之泛型解说

    1.集合中只能装入引用数据类型,不能装入基本数据类型.如,装入int类型的数值123会自动装箱. 2.开发人员装入集合的数据类型不确定,所以它被设计成可以装入所有的Object. 3.新的问题产生,装 ...

  6. C#中ListView易错的方法

    现在有一个ListView(lv1),有2列. ListViewItem lvi = new ListViewItem(); lvi.Text = "语文"; lvi.SubIte ...

  7. jQuery购物车

    效果图 HTML代码:(非表格方式) <div class="nav2"> <input type="checkbox" class=&quo ...

  8. Mesos+Zookeeper+Marathon+Docker分布式集群管理最佳实践

    参考赵班长的unixhot以及马亮blog 笔者QQ:572891887 Linux架构交流群:471443208 1.1Mesos简介 Mesos是Apache下的开源分布式资源管理框架,它被称为分 ...

  9. [转]使用sklearn进行集成学习——实践

    转:http://www.cnblogs.com/jasonfreak/p/5720137.html 目录 1 Random Forest和Gradient Tree Boosting参数详解2 如何 ...

  10. (iOS)关于UITableView设置contentsize(原创)

    由于UITableView是继承自UIScrollView的,所以他是可以设置contentsize的. 但是,我在试验的过程中,初始化UITableView实例后,直接设置它的contentsize ...