package net.dubboclub.tracing.client.util; import com.alibaba.dubbo.common.utils.StringUtils; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.math.BigInteger; import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.channels.FileChannel; /** * Created by Zetas on 2016/7/8. */ public class GUId { private final long maxId = 1 << 10; private final long maxSequence = 1 << 12; private final short timeShiftLeft = 64; private final short sequenceShiftLeft = 42; private final short idShiftLeft = 32; private final short ipShiftLeft = 0; private BigInteger ip; private BigInteger id; private long sequence; private long lastTimestamp; private static class Holder { private static GUId instance; static { try { instance = new GUId(); } catch (IOException e) { e.printStackTrace(); } } } private GUId() throws IOException { long ipTmp = ip(); long idTmp = id(); if (ipTmp < 0 || idTmp < 0) { throw new IllegalArgumentException("can not be less than 0"); } ip = BigInteger.valueOf(ipTmp).shiftLeft(ipShiftLeft); id = BigInteger.valueOf(idTmp).shiftLeft(idShiftLeft); } public static GUId singleton() { return Holder.instance; } public synchronized String nextId() { long timestamp = timeGen(); if (lastTimestamp == timestamp) { sequence = sequence + 1 & maxSequence; if (sequence == 0) { timestamp = tilNextMillis(lastTimestamp); } } else { sequence = 0; } lastTimestamp = timestamp; BigInteger time = BigInteger.valueOf(timestamp).shiftLeft(timeShiftLeft); BigInteger seq = BigInteger.valueOf(sequence).shiftLeft(sequenceShiftLeft); return time.or(seq).or(id).or(ip).toString(32); } private long ip() throws UnknownHostException { InetAddress inetAddress = InetAddress.getLocalHost(); byte[] address = inetAddress.getAddress(); long a = (long) (address[0] & 0xff) << 24; long b = (long) (address[1] & 0xff) << 16; long c = (long) (address[2] & 0xff) << 8; long d = (long) (address[3] & 0xff); return a | b | c | d; } private long id() throws IOException { String userHome = System.getProperty("user.home"); if (StringUtils.isNotEmpty(userHome)) { File dstDirectory = new File(userHome, ".dst"); boolean dstDirectoryExists = dstDirectory.exists(); if (!dstDirectoryExists) { dstDirectoryExists = dstDirectory.mkdir(); } if (dstDirectoryExists) { File lock = new File(dstDirectory, "unique-id.lock"); boolean lockExists = dstDirectory.exists(); if (!lockExists) { lockExists = lock.createNewFile(); } if (lockExists) { RandomAccessFile randomAccessFile = new RandomAccessFile(lock, "rw"); FileChannel fileChannel = randomAccessFile.getChannel(); for (int i = 0; i < maxId; i++) { if (fileChannel.tryLock(i, 1, false) != null) { return i; } } } } } return -1; } private long tilNextMillis(long lastTimestamp) { long timestamp = timeGen(); while (timestamp <= lastTimestamp) { timestamp = timeGen(); } return timestamp; } private static long timeGen() { return System.currentTimeMillis(); } public static void main(String[] args) { for (int i = 0; i < 10; i++) { System.out.println(GUId.singleton().nextId()); } } }