ULID规范解读与实现原理( 五 )

关于上一个ULID和下一个ULID之间的时间戳判断 , 这里从规范文件没看出细节实现 , 先简单做一个永远为true的分支判断 , 后面再深入研究然后修改 。使用方式如下:
public static void main(String[] args) {MonotonicULIDSpi spi = ULID.monotonicUlid();System.out.println(spi.next());System.out.println(spi.next());System.out.println(spi.next());System.out.println(spi.next());}// 某次运行输出01GFGASXXQXD5ZJ26PKSCFGNPF01GFGASXXQXD5ZJ26PKSCFGNPG01GFGASXXQXD5ZJ26PKSCFGNPH01GFGASXXQXD5ZJ26PKSCFGNPJ这里为了更加灵活 , 没有采用全局静态属性缓存上一个ULID实例 , 而是简单使用继承方式实现 。
ULID性能评估引入JMH做了一个简单的性能测试 , 代码如下:
@Fork(1)@Threads(10)@State(Scope.Benchmark)@BenchmarkMode(Mode.Throughput)@Warmup(iterations = 1, time = 1)@Measurement(iterations = 5, time = 3)@OutputTimeUnit(TimeUnit.MILLISECONDS)public class BenchmarkRunner {private static ULID.MonotonicULIDSpi SPI;@Setuppublic void setup() {SPI = ULID.monotonicUlid();}@Benchmarkpublic UUID createUUID() {return UUID.randomUUID();}@Benchmarkpublic String createUUIDToString() {return UUID.randomUUID().toString();}@Benchmarkpublic ULID createULID() {return ULID.ulid();}@Benchmarkpublic String createULIDToString() {return ULID.ulid().toString();}@Benchmarkpublic String createULIDToCanonicalString0() {return ULID.ulid().toCanonicalString0();}@Benchmarkpublic ULID createMonotonicULID() {return SPI.next();}@Benchmarkpublic String createMonotonicULIDToString() {return SPI.next().toString();}public static void main(String[] args) throws Exception {new Runner(new OptionsBuilder().build()).run();}}某次测试报告如下(开发环境Intel 6700K 4C8T 32G , 使用OpenJDK-19):
BenchmarkModeCntScoreErrorUnitsBenchmarkRunner.createMonotonicULIDthrpt518529.565 ± 3432.113ops/msBenchmarkRunner.createMonotonicULIDToStringthrpt512308.443 ± 1729.675ops/msBenchmarkRunner.createULIDthrpt5122347.702 ± 3183.734ops/msBenchmarkRunner.createULIDToCanonicalString0thrpt550848.135 ± 3699.334ops/msBenchmarkRunner.createULIDToStringthrpt537346.891 ± 1029.809ops/msBenchmarkRunner.createUUIDthrpt5806.134 ±218.622ops/msBenchmarkRunner.createUUIDToStringthrpt5813.380 ±46.333ops/ms小结本文就ULID的规范进行解读 , 通过规范和参考现有类库进行ULIDJava实现 。ULID适用于一些"排序ID"生成或者需要"单调ID"生成的场景 , 可以考虑用于数据库键设计、顺序号设计等等场景 。从实现上看它性能会优于UUID(特别是单调ULID , 因为不需要重新获取随机数部分 , 吞吐量会提升一个数量级) 。
Demo项目仓库:

  • framework-mesh/ulid4jhttps://github.com/zjcscut/framework-mesh/tree/master/ulid4j
参考资料:
  • ulid-spec
  • crockford-base32
  • ulid-creator
【ULID规范解读与实现原理】

经验总结扩展阅读