本文目录导读:

我将为您提供几个Java实现分布式ID的完整案例,涵盖不同方案。
雪花算法(Snowflake)实现
基础版本
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.atomic.AtomicLong;
public class SnowflakeIdGenerator {
// 起始时间戳 (2020-01-01)
private static final long START_TIME = 1577808000000L;
// 各部分占用的位数
private static final long SEQUENCE_BITS = 12; // 序列号占12位
private static final long MACHINE_ID_BITS = 5; // 机器ID占5位
private static final long DATACENTER_ID_BITS = 5; // 数据中心ID占5位
// 各部分最大值
private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);
private static final long MAX_MACHINE_ID = ~(-1L << MACHINE_ID_BITS);
private static final long MAX_DATACENTER_ID = ~(-1L << DATACENTER_ID_BITS);
// 各部分向左的位移
private static final long MACHINE_ID_SHIFT = SEQUENCE_BITS;
private static final long DATACENTER_ID_SHIFT = SEQUENCE_BITS + MACHINE_ID_BITS;
private static final long TIMESTAMP_SHIFT = SEQUENCE_BITS + MACHINE_ID_BITS + DATACENTER_ID_BITS;
private final long datacenterId; // 数据中心ID
private final long machineId; // 机器ID
private long sequence = 0L; // 序列号
private long lastTimestamp = -1L; // 上次生成ID的时间戳
public SnowflakeIdGenerator(long datacenterId, long machineId) {
if (datacenterId > MAX_DATACENTER_ID || datacenterId < 0) {
throw new IllegalArgumentException("datacenterId must be between 0 and " + MAX_DATACENTER_ID);
}
if (machineId > MAX_MACHINE_ID || machineId < 0) {
throw new IllegalArgumentException("machineId must be between 0 and " + MAX_MACHINE_ID);
}
this.datacenterId = datacenterId;
this.machineId = machineId;
}
public synchronized long nextId() {
long currentTimestamp = System.currentTimeMillis();
if (currentTimestamp < lastTimestamp) {
throw new RuntimeException("Clock moved backwards. Refusing to generate id");
}
if (currentTimestamp == lastTimestamp) {
sequence = (sequence + 1) & MAX_SEQUENCE;
if (sequence == 0) {
// 序列号用尽,等待下一毫秒
currentTimestamp = waitNextMillis(lastTimestamp);
}
} else {
sequence = 0L;
}
lastTimestamp = currentTimestamp;
return ((currentTimestamp - START_TIME) << TIMESTAMP_SHIFT)
| (datacenterId << DATACENTER_ID_SHIFT)
| (machineId << MACHINE_ID_SHIFT)
| sequence;
}
private long waitNextMillis(long lastTimestamp) {
long currentTimestamp = System.currentTimeMillis();
while (currentTimestamp <= lastTimestamp) {
currentTimestamp = System.currentTimeMillis();
}
return currentTimestamp;
}
// 获取本机IP地址生成workerId
public static long getWorkerId() {
try {
InetAddress ip = InetAddress.getLocalHost();
byte[] ipAddress = ip.getAddress();
return ((ipAddress[ipAddress.length - 1] & 0xFF) % 32);
} catch (UnknownHostException e) {
return Math.abs(java.util.UUID.randomUUID().hashCode()) % 32;
}
}
}
使用示例
public class SnowflakeExample {
public static void main(String[] args) {
// 创建生成器
SnowflakeIdGenerator generator = new SnowflakeIdGenerator(1, 1);
// 生成单个ID
long id = generator.nextId();
System.out.println("生成的ID: " + id);
// 批量生成
for (int i = 0; i < 10; i++) {
System.out.println("ID " + (i+1) + ": " + generator.nextId());
}
// 并发测试
ExecutorService executor = Executors.newFixedThreadPool(10);
Set<Long> ids = ConcurrentHashMap.newKeySet();
for (int i = 0; i < 1000; i++) {
executor.submit(() -> {
long newId = generator.nextId();
ids.add(newId);
});
}
executor.shutdown();
try {
executor.awaitTermination(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("生成的唯一ID数量: " + ids.size());
}
}
基于数据库的ID生成方案
数据库表结构
CREATE TABLE `distributed_id` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `biz_type` varchar(50) NOT NULL COMMENT '业务类型', PRIMARY KEY (`id`), UNIQUE KEY `uk_biz_type` (`biz_type`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Java实现
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class DatabaseIdGenerator {
private final DataSource dataSource;
private final int step; // 步长
public DatabaseIdGenerator(DataSource dataSource, int step) {
this.dataSource = dataSource;
this.step = step;
}
public long generateId(String bizType) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = dataSource.getConnection();
// 更新并获取新的ID范围
String sql = "UPDATE distributed_id SET id = LAST_INSERT_ID(id + ?) WHERE biz_type = ?";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, step);
pstmt.setString(2, bizType);
pstmt.executeUpdate();
// 获取当前ID
sql = "SELECT LAST_INSERT_ID()";
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
if (rs.next()) {
return rs.getLong(1) - step + 1;
}
return -1;
} catch (SQLException e) {
throw new RuntimeException("Failed to generate ID", e);
} finally {
// 关闭资源
try {
if (rs != null) rs.close();
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
批量获取IDRange
public class IdRange {
private final long minId;
private final long maxId;
private long currentId;
public IdRange(long minId, long maxId) {
this.minId = minId;
this.maxId = maxId;
this.currentId = minId;
}
public synchronized long nextId() {
if (currentId > maxId) {
return -1; // 范围已用尽
}
return currentId++;
}
public boolean isExhausted() {
return currentId > maxId;
}
public long getMinId() { return minId; }
public long getMaxId() { return maxId; }
public long getCurrentId() { return currentId; }
}
Redis原子操作方案
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.params.SetParams;
public class RedisIdGenerator {
private final JedisPool jedisPool;
private final String keyPrefix;
private final int step = 100; // 步长
public RedisIdGenerator(JedisPool jedisPool, String keyPrefix) {
this.jedisPool = jedisPool;
this.keyPrefix = keyPrefix;
}
public long generateId(String bizType) {
String key = keyPrefix + ":" + bizType;
try (Jedis jedis = jedisPool.getResource()) {
// 使用INCR命令原子递增
return jedis.incr(key);
}
}
// 批量获取ID(每批次减少网络开销)
public IdRange generateIdRange(String bizType) {
String key = keyPrefix + ":" + bizType;
try (Jedis jedis = jedisPool.getResource()) {
long minId = jedis.incrBy(key, step) - step + 1;
long maxId = minId + step - 1;
// 初始化缓存中的id范围
return new IdRange(minId, maxId);
}
}
// 使用Lua脚本保证原子性
public long generateIdWithLua(String bizType, int count) {
String key = keyPrefix + ":" + bizType;
String luaScript =
"local current = redis.call('GET', KEYS[1]) " +
"if not current then current = 0 end " +
"local next = tonumber(current) + tonumber(ARGV[1]) " +
"redis.call('SET', KEYS[1], next) " +
"return next";
try (Jedis jedis = jedisPool.getResource()) {
Object result = jedis.eval(luaScript, 1, key, String.valueOf(count));
return Long.parseLong(result.toString());
}
}
}
UUID方案(简单但有缺点)
import java.util.UUID;
public class UUIDGenerator {
// 标准UUID
public String generateUUID() {
return UUID.randomUUID().toString();
}
// 去除连字符的UUID
public String generateUUIDWithoutDash() {
return UUID.randomUUID().toString().replace("-", "");
}
// 数字格式的UUID(适合作为Long类型ID)
public Long generateNumericId() {
return Math.abs(UUID.randomUUID().getMostSignificantBits());
}
// 转化为Base64缩短长度
public String generateShortUUID() {
UUID uuid = UUID.randomUUID();
byte[] bytes = new byte[16];
long most = uuid.getMostSignificantBits();
long least = uuid.getLeastSignificantBits();
for (int i = 0; i < 8; i++) {
bytes[i] = (byte) (most >>> (56 - i * 8));
bytes[8 + i] = (byte) (least >>> (56 - i * 8));
}
return java.util.Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
}
}
完整生产级方案(组合实现)
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
public class DistributedIdGenerator {
// 配置
private static class IdConfig {
final long datacenterId;
final long workerId;
final long timestampBits = 41;
final long datacenterBits = 5;
final long workerBits = 5;
final long sequenceBits = 12;
final long maxSequence = ~(-1L << sequenceBits);
final long maxWorker = ~(-1L << workerBits);
final long maxDatacenter = ~(-1L << datacenterBits);
final long workerShift = sequenceBits;
final long datacenterShift = sequenceBits + workerBits;
final long timestampShift = sequenceBits + workerBits + datacenterBits;
long startTimestamp = 1577808000000L; // 2020-01-01
final long maxTimestamp = ~(-1L << timestampBits) + startTimestamp;
IdConfig(long datacenterId, long workerId) {
if (datacenterId > maxDatacenter || datacenterId < 0) {
throw new IllegalArgumentException("Invalid datacenterId");
}
if (workerId > maxWorker || workerId < 0) {
throw new IllegalArgumentException("Invalid workerId");
}
this.datacenterId = datacenterId;
this.workerId = workerId;
}
}
// 各种生成器实例
private final SnowflakeIdGenerator snowflakeGenerator;
private final RedisIdGenerator redisGenerator;
private final DatabaseIdGenerator databaseGenerator;
private final UUIDGenerator uuidGenerator;
// 缓存用于当前ID生成策略
private final ConcurrentHashMap<String, AtomicLong> idCache = new ConcurrentHashMap<>();
public DistributedIdGenerator() {
// 初始化各生成器
this.snowflakeGenerator = new SnowflakeIdGenerator(1, 1);
this.redisGenerator = null; // 需要配置Redis连接池
this.databaseGenerator = null; // 需要配置数据源
this.uuidGenerator = new UUIDGenerator();
}
// 根据不同的业务场景选择合适的ID生成策略
public long generateSnowflakeId() {
return snowflakeGenerator.nextId();
}
public String generateUUID() {
return uuidGenerator.generateUUIDWithoutDash();
}
// 带缓存策略的ID生成
public long generateCachedId(String bizType) {
AtomicLong cache = idCache.computeIfAbsent(bizType, k -> new AtomicLong(0));
long id = cache.getAndIncrement();
// 如果缓存中的ID不够用,从数据库获取新的范围
if (id >= 1000000) { // 假设每100万需要刷新
// 从数据库获取新的ID范围
// idCache.put(bizType, new AtomicLong(newRangeStart));
}
return id;
}
}
使用示例
public class DistributedIdDemo {
public static void main(String[] args) {
// 1. 雪花算法
SnowflakeIdGenerator snowflake = new SnowflakeIdGenerator(1, 1);
System.out.println("雪花算法 ID: " + snowflake.nextId());
// 2. UUID
UUIDGenerator uuidGen = new UUIDGenerator();
System.out.println("UUID: " + uuidGen.generateUUIDWithoutDash());
// 3. 并发测试
ConcurrentHashMap<Long, Boolean> idSet = new ConcurrentHashMap<>();
ExecutorService executor = Executors.newFixedThreadPool(20);
long startTime = System.currentTimeMillis();
// 提交10000个任务
CountDownLatch latch = new CountDownLatch(10000);
for (int i = 0; i < 10000; i++) {
executor.submit(() -> {
long id = snowflake.nextId();
idSet.put(id, true);
latch.countDown();
});
}
try {
latch.await(10, TimeUnit.SECONDS);
long endTime = System.currentTimeMillis();
System.out.println("生成10000个唯一ID数量: " + idSet.size());
System.out.println("耗时: " + (endTime - startTime) + "ms");
System.out.println("平均耗时: " + (startTime - endTime) / 10000.0 + "ms/个");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
executor.shutdown();
}
}
}
最佳实践建议
public class IdGeneratorFactory {
// 根据业务需求选择合适的ID生成策略
public static IdGeneratorStrategy createStrategy(IdType type, IdConfig config) {
switch (type) {
case SNOWFLAKE:
return new SnowflakeStrategy(config);
case REDIS:
return new RedisStrategy(config);
case DATABASE:
return new DatabaseStrategy(config);
case MIXED:
return new MixedStrategy(config);
default:
throw new IllegalArgumentException("Unsupported ID type");
}
}
enum IdType {
SNOWFLAKE, // 雪花算法
REDIS, // Redis生成
DATABASE, // 数据库生成
MIXED // 混合策略
}
interface IdGeneratorStrategy {
long nextId(String bizType);
String nextIdString(String bizType);
}
static class SnowflakeStrategy implements IdGeneratorStrategy {
private final SnowflakeIdGenerator generator;
SnowflakeStrategy(IdConfig config) {
this.generator = new SnowflakeIdGenerator(config.datacenterId, config.workerId);
}
@Override
public long nextId(String bizType) {
return generator.nextId();
}
@Override
public String nextIdString(String bizType) {
return String.valueOf(generator.nextId());
}
}
// 其他策略实现...
}
方案对比
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 雪花算法 | 高性能、趋势递增、无网络依赖 | 依赖机器时钟 | 高并发分布式环境 |
| 数据库 | 简单、可靠 | 性能瓶颈、需维护 | 小规模系统 |
| Redis | 高性能、灵活 | 依赖Redis、持久化问题 | 中高并发系统 |
| UUID | 简单、全局唯一 | 无序、存储浪费 | 非索引字段 |
选择合适的方案需要根据业务场景、并发量、系统架构等因素综合考虑,建议在实际生产环境中结合多种方案使用。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播