-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
238 additions
and
140 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
21 changes: 0 additions & 21 deletions
21
framework/game-utils/src/main/java/com/lzh/game/framework/utils/IdGenerator.java
This file was deleted.
Oops, something went wrong.
108 changes: 0 additions & 108 deletions
108
framework/game-utils/src/main/java/com/lzh/game/framework/utils/SnowFlake.java
This file was deleted.
Oops, something went wrong.
10 changes: 10 additions & 0 deletions
10
framework/game-utils/src/main/java/com/lzh/game/framework/utils/id/IdGenerator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.lzh.game.framework.utils.id; | ||
|
||
/** | ||
* @author zehong.l | ||
* @since 2025-01-07 15:12 | ||
**/ | ||
public interface IdGenerator { | ||
|
||
long nextId(); | ||
} |
30 changes: 30 additions & 0 deletions
30
framework/game-utils/src/main/java/com/lzh/game/framework/utils/id/IdGeneratorHelp.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package com.lzh.game.framework.utils.id; | ||
|
||
import java.util.Objects; | ||
|
||
/** | ||
* Id生成器 | ||
*/ | ||
public class IdGeneratorHelp { | ||
|
||
private static IdGenerator idGenerator; | ||
|
||
private IdGeneratorHelp() {} | ||
|
||
public static void setIdGenerator(IdGenerator id) { | ||
synchronized (IdGeneratorHelp.class) { | ||
idGenerator = id; | ||
} | ||
} | ||
|
||
public static long nextId() { | ||
if (Objects.isNull(idGenerator)) { | ||
synchronized (IdGeneratorHelp.class) { | ||
if (Objects.isNull(idGenerator)) { | ||
idGenerator = new SnowflakeIdGenerator(1); | ||
} | ||
} | ||
} | ||
return idGenerator.nextId(); | ||
} | ||
} |
149 changes: 149 additions & 0 deletions
149
framework/game-utils/src/main/java/com/lzh/game/framework/utils/id/SnowflakeIdGenerator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
package com.lzh.game.framework.utils.id; | ||
|
||
/** | ||
* Unsafe | ||
* | ||
* Distributed Sequence Generator. | ||
* Inspired by Twitter snowflake: https://github.com/twitter/snowflake/tree/snowflake-2010 | ||
* | ||
* This class should be used as a Singleton. | ||
* Make sure that you create and reuse a Single instance of SequenceGenerator per node in your distributed system cluster. | ||
*/ | ||
/** | ||
* Snowflake ID Generator | ||
* | ||
* Generates unique distributed IDs with the following bit allocation: | ||
* - 1 bit: Sign bit (always 0) | ||
* - 41 bits: Timestamp (milliseconds since custom epoch) | ||
* - 10 bits: Machine/Worker ID | ||
* - 12 bits: Sequence number | ||
*/ | ||
public class SnowflakeIdGenerator implements IdGenerator { | ||
// Configuration constants | ||
private static final long CUSTOM_EPOCH = 1609459200000L; // Jan 1, 2021 | ||
private static final int WORKER_ID_BITS = 10; | ||
private static final int SEQUENCE_BITS = 12; | ||
|
||
// Bit shift positions | ||
private static final int WORKER_ID_SHIFT = SEQUENCE_BITS; | ||
private static final int TIMESTAMP_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS; | ||
|
||
// Maximum values for worker ID and sequence | ||
private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS); | ||
private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS); | ||
|
||
// Instance variables | ||
private final long workerId; | ||
private long lastTimestamp = -1L; | ||
private long sequence = 0L; | ||
|
||
/** | ||
* Constructor for SnowflakeIdGenerator | ||
* | ||
* @param workerId Unique identifier for this worker/machine (0-1023) | ||
*/ | ||
public SnowflakeIdGenerator(long workerId) { | ||
if (workerId < 0 || workerId > MAX_WORKER_ID) { | ||
throw new IllegalArgumentException(String.format( | ||
"Worker ID must be between 0 and %d", MAX_WORKER_ID)); | ||
} | ||
this.workerId = workerId; | ||
} | ||
|
||
/** | ||
* Generate a unique Snowflake ID | ||
* | ||
* @return Unique 64-bit long ID | ||
*/ | ||
@Override | ||
public long nextId() { | ||
long currentTimestamp = getCurrentTimestamp(); | ||
|
||
// Handle clock drift or system time changes | ||
if (currentTimestamp < lastTimestamp) { | ||
throw new RuntimeException("Clock moved backwards. Refusing to generate ID."); | ||
} | ||
|
||
// If same millisecond, increment sequence | ||
if (currentTimestamp == lastTimestamp) { | ||
sequence = (sequence + 1) & MAX_SEQUENCE; | ||
|
||
// If sequence overflows, wait for next millisecond | ||
if (sequence == 0) { | ||
currentTimestamp = waitNextMillis(currentTimestamp); | ||
} | ||
} else { | ||
// Reset sequence for new timestamp | ||
sequence = 0L; | ||
} | ||
|
||
// Update last timestamp | ||
lastTimestamp = currentTimestamp; | ||
|
||
// Construct the unique ID | ||
return ((currentTimestamp - CUSTOM_EPOCH) << TIMESTAMP_SHIFT) | | ||
(workerId << WORKER_ID_SHIFT) | | ||
sequence; | ||
} | ||
|
||
/** | ||
* Get current timestamp in milliseconds | ||
* | ||
* @return Current timestamp | ||
*/ | ||
private long getCurrentTimestamp() { | ||
return System.currentTimeMillis(); | ||
} | ||
|
||
/** | ||
* Wait for next millisecond if current timestamp is the same | ||
* | ||
* @param currentTimestamp Current timestamp | ||
* @return Next unique timestamp | ||
*/ | ||
private long waitNextMillis(long currentTimestamp) { | ||
long timestamp = getCurrentTimestamp(); | ||
while (timestamp <= currentTimestamp) { | ||
timestamp = getCurrentTimestamp(); | ||
} | ||
return timestamp; | ||
} | ||
|
||
/** | ||
* Extract components from a Snowflake ID | ||
* | ||
* @param id Snowflake ID | ||
* @return Breakdown of ID components | ||
*/ | ||
public static IdComponents parseId(long id) { | ||
long timestamp = ((id >> TIMESTAMP_SHIFT) & ((1L << 41) - 1)) + CUSTOM_EPOCH; | ||
long workerId = (id >> WORKER_ID_SHIFT) & ((1L << WORKER_ID_BITS) - 1); | ||
long sequence = id & ((1L << SEQUENCE_BITS) - 1); | ||
|
||
return new IdComponents(timestamp, workerId, sequence); | ||
} | ||
|
||
/** | ||
* Represents components of a Snowflake ID | ||
*/ | ||
public static class IdComponents { | ||
public final long timestamp; | ||
public final long workerId; | ||
public final long sequence; | ||
|
||
public IdComponents(long timestamp, long workerId, long sequence) { | ||
this.timestamp = timestamp; | ||
this.workerId = workerId; | ||
this.sequence = sequence; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return String.format( | ||
"Timestamp: %d, Worker ID: %d, Sequence: %d", | ||
timestamp, workerId, sequence | ||
); | ||
} | ||
} | ||
|
||
} |
2 changes: 1 addition & 1 deletion
2
...lzh/game/framework/utils/RandomUtils.java → ...e/framework/utils/random/RandomUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.