• 参考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. 数据库中的T-sql语句 条件修改 高级查询

    1.创建数据库:create database --数据库名,不能中文,不能数字开头,不能符号开头 2.删除数据库:drop database-- 数据库名 use student--使用数据库 3. ...

  2. Visual Studio 2017 ASP.NET Core开发

    Visual Studio 2017 ASP.NET Core开发,Visual Studio 2017 已经内置ASP.NET Core 开发工具. 在选择.NET Core 功能安装以后就可以进行 ...

  3. node.js爬虫爬取拉勾网职位信息

    简介 用node.js写了一个简单的小爬虫,用来爬取拉勾网上的招聘信息,共爬取了北京.上海.广州.深圳.杭州.西安.成都7个城市的数据,分别以前端.PHP.java.c++.python.Androi ...

  4. opencv与VS的配置

    1.VS2015下配置Opencv3.2教程:http://jingyan.baidu.com/article/4b52d702b3209afc5c774b3c.html http://blog.cs ...

  5. Android自学反思总结(下)

    后来陆陆续续过了大半个月,导员给找了一个Udacity在线学习的Android开发教程,只有一个月的免费学习机会,因此很快开始了叫Sunshine的天气应用的开发,教学视频整体是采用先自己思考并填写某 ...

  6. java学习笔记 --- 方法

    一.方法  (1)方法:就是完成特定功能的代码块.   注意:在很多语言里面有函数的定义,而在Java中,函数被称为方法.  (2)格式:   修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 ...

  7. iOS开发之视频播放

    1.如何播放视频 iOS提供了MPMoviePlayerController.MPMoviePlayerViewController两个类,可以用来轻松播放视频和网络流媒体\网络音频. 提示:网络音频 ...

  8. shell脚本监控目录下文件被篡改时报警

    思路: 目录下文件被篡改的几种可能: 1.被修改 2.被删除 3.新增文件 md5命令详解 参数: -b 以二进制模式读入文件内容 -t 以文本模式读入文件内容 -c 根据已生成的md5值,对现存文件 ...

  9. 解决codeblock不能运行的问题

    codeblock 编译失败 软件 IDE codeblock这软件的确不错,但是除此安装使用就会不小心入坑.你是不是满心欢喜的下载好codeblock,敲入代码,点击运行的时候却总是没反应呢? 如果 ...

  10. (转)python中的*args和**kw到底是个啥。看下面的例子就会懂了

    先来看个例子: def foo(*args, **kwargs): print 'args = ', args print 'kwargs = ', kwargs print '----------- ...