IdGeneratorService { public synchronized long generate(int shardId) { if (shardId > maxShardId || shardId < 0) { throw new IllegalArgumentException(format("Shard id can't be greater than %s or less than 0", maxShardId)); } long ts = currentTimeMillis(); if (ts < lastTimestamp) { log.error("Clock is moving backwards. Rejecting requests until {}.", lastTimestamp); throw new IllegalStateException(format("Clock moved backwards. Refusing to generate id for %s milliseconds", lastTimestamp - ts)); } if (lastTimestamp == ts || lastTimestamp < 0) { sequence++; } else { sequence = 0; } if (sequence > maxSequenceId) { ts = getNextMills(lastTimestamp); sequence = 0; } lastTimestamp = ts; return ((ts - epoch) << timestampLeftShift) | (shardId << shardIdShift) | sequence; }  synchronized long generate(int shardId); int getShard(long id); long getTimestamp(long id); HashCode getHash(long id);  }
@Test public void multiThread() throws InterruptedException { int threads = 64; final int idsNum = 10000; final IdGeneratorService service = new IdGeneratorService(); ExecutorService executorService = newFixedThreadPool(threads * 2); final CountDownLatch latch = new CountDownLatch(threads); final ConcurrentHashMap<Long, Boolean> ids = new ConcurrentHashMap<>(); for (int i = 0; i < threads; i++) { executorService.submit( new Runnable() { @Override public void run() { try { for (int j = 0; j < idsNum; j++) { long id = service.generate(1); if (null != ids.putIfAbsent(id, true)) { throw new RuntimeException("" + id); } } } catch (Exception e) { log.error("Exception", e); } finally { latch.countDown(); } } } ); } latch.await(); assertEquals(ids.size(), threads * idsNum); }
@Test public void generateId() { IdGeneratorService idGeneratorService = new IdGeneratorService(); log.info("id {}", idGeneratorService.generate(1)); }
@Test public void generateSingleThread() { Set<Long> ids = new HashSet<>(); IdGeneratorService idGeneratorService = new IdGeneratorService(); for (int i = 0; i < 4096; i++) { long id = idGeneratorService.generate(1); assertTrue(ids.add(id)); } }