Java每天唯一递增序列
在很多实际应用中,我们需要生成一个每天唯一递增的序列,用来作为订单号、流水号等标识。这里我们将介绍如何使用Java来实现这样一个功能。
为什么需要每天唯一递增序列
在很多业务中,我们需要生成一个唯一的序列号来标识每一次操作或者交易。而每天唯一递增的序列号对于日志记录、数据统计等方面都具有很大的价值。通过每天唯一递增序列,我们可以更加方便地对数据进行归类和统计,使得系统更加健壮和稳定。
实现方法
日期+序号
一种简单的实现方式是将日期和序号结合起来生成唯一序列。每天开始时序号从1开始递增,直到当天结束。第二天再次从1开始递增。这种方式简单易懂,但是在高并发情况下可能存在性能瓶颈。
分布式ID生成器
另一种方式是使用分布式ID生成器,比如Snowflake算法。这种算法生成的ID是一个64位的整数,其中包含了时间戳、机器ID、序列号等信息,具有全局唯一性并且递增有序。这种方式适合高并发场景下的ID生成需求。
代码示例
日期+序号实现
public class DailySerialNumberGenerator {
private static LocalDate currentDate;
private static int currentNumber = 0;
public synchronized static String generateSerialNumber() {
LocalDate today = LocalDate.now();
if (!today.equals(currentDate)) {
currentDate = today;
currentNumber = 0;
}
currentNumber++;
return today.toString() + String.format("%04d", currentNumber);
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println(generateSerialNumber());
}
}
}
Snowflake算法实现
public class SnowflakeIdWorker {
private final long twepoch = 1288834974657L;
private final long workerIdBits = 5L;
private final long datacenterIdBits = 5L;
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
private final long sequenceBits = 12L;
private final long workerIdShift = sequenceBits;
private final long datacenterIdShift = sequenceBits + workerIdBits;
private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
private long workerId;
private long datacenterId;
private long sequence = 0L;
private long lastTimestamp = -1L;
public SnowflakeIdWorker(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException("workerId can't be greater than " + maxWorkerId + " or less than 0");
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException("datacenterId can't be greater than " + maxDatacenterId + " or less than 0");
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
public synchronized long nextId() {
long timestamp = System.currentTimeMillis();
if (timestamp < lastTimestamp) {
throw new RuntimeException("Clock moved backwards. Refusing to generate id");
}
if (timestamp == lastTimestamp) {
sequence = (sequence + 1) & sequenceMask;
if (sequence == 0) {
timestamp = tilNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = timestamp;
return ((timestamp - twepoch) << timestampLeftShift) |
(datacenterId << datacenterIdShift) |
(workerId << workerIdShift) |
sequence;
}
private long tilNextMillis(long lastTimestamp) {
long timestamp = System.currentTimeMillis();
while (timestamp <= lastTimestamp) {
timestamp = System.currentTimeMillis();
}
return timestamp;
}
public static void main(String[] args) {
SnowflakeIdWorker idWorker = new SnowflakeIdWorker(1, 1);
for (int i =