• 参考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. 说说如何用js实现一个模板引擎

    本文同步更新在: https://github.com/whxaxes/blog/issues/4 ,在 github 看文章显示效果会更好一些. 前言 不知不觉就很长时间没造过什么轮子了,以前一直想 ...

  2. 获取手机 IP

    /** *  获取用户ip * *  @return 获取用户ip */ + (NSString *)getIPAddress { NSString *address = @"an erro ...

  3. a中的类型转换

    自动类型转换 当然自动类型转换是需要满足特定的条件的: 1.  目标类型能与源类型兼容,如 double 型兼容 int 型,但是 char 型不能兼容 int 型. 2.  目标类型大于源类型,如 ...

  4. [OpenGL] mac上运行NateRobin的OpenGL教程找不到 data file 解决方案

    之前买的OpenGL编程指南第七版一直没看,最近开始看了,然后按照教程推荐的去指定网址下载NateRobin的OpenGL教程,但发现网址已经提示Error:404了, 然后谷歌搜索到可用的下载网址为 ...

  5. Servlet中的过滤器Filter详解

    加载执行顺序 context-param->listener->filter->servlet web.xml中元素执行的顺序listener->filter->stru ...

  6. solr home 目录设置

    对于在tomcat 中部署solr 来说,有以下三处可以配置 solr.solr.home(即solr的数据文件位置): 1. 在解压缩solr.war后的webapps/solr 中的WEB-INF ...

  7. Cannot use ImageField because Pillow is not installed.

    现象描述: 使用 ImageField ,创建数据库表时,提示如下: Cannot use ImageField because Pillow is not installed. HINT: Get ...

  8. 联想A7600-m刷机心得

    先来说说刷机 联想A7600-m的刷机

  9. SLF4J 的几种实际应用模式--之三:JCL-Over-SLF4J+SLF4J

    我们前面已经讲过了 SLF4J 的两种用法:SLF4J+Log4J  和 SLF4J+Logback,那是在比较理想的情况下,所用组件只使用了 SLF4J 这一种统一日志框架的时候.可是 JCL 一直 ...

  10. 降低Redis内存占用

    1.降低redis内存占用的优点 1.有助于减少创建快照和加载快照所用的时间 2.提升载入AOF文件和重写AOF文件时的效率 3.缩短从服务器进行同步所需的时间 4.无需添加额外的硬件就可以让redi ...