雪花算法-通用

import java.util.concurrent.ConcurrentHashMap;

/**
 * @author L.yn
 * @date 2021-07-19 10:34
 */
public class SnowflakeIdHolder {
    private SnowflakeIdHolder() {
    }

    private static final ConcurrentHashMap<String, SnowflakeIdUtils> HOLDER = new ConcurrentHashMap<>();

    public static SnowflakeIdUtils getSnowflakeIdUtils(String name) {
        SnowflakeIdUtils snowflakeIdUtils = HOLDER.get(name);
        if (snowflakeIdUtils == null) {
            snowflakeIdUtils = HOLDER.computeIfAbsent(name, n -> new SnowflakeIdUtils(SnowflakeIdConfig.getWorkerId()));
        }
        return snowflakeIdUtils;
    }

    /**
     * 生成下一个雪花ID
     *
     * @return 唯一雪花id
     */
    public static long genId(String name) {
        return getSnowflakeIdUtils(name).genId();
    }

//    /**
//     * 生成易识别的下一个雪花ID,目前会重复,不建议使用
//     *
//     * @return 唯一雪花id
//     */
//    @Deprecated
//    public static long genFormatId(String name) {
//        return getSnowflakeIdUtils(name).genFormatId();
//    }
//
//    /**
//     * 生成易识别的下一个雪花ID
//     *
//     * @return 唯一雪花id
//     */
//    public static String genFormatIdStr(String name) {
//        return getSnowflakeIdUtils(name).genFormatIdStr();
//    }

}

/**
 * @author L.yn
 * @date 2021-07-19 10:34
 */
@Slf4j
public class SnowflakeIdConfig implements InitializingBean {

	private static int workGroupIdBits = 2;
	private static String localIp;

	static {
		String ip = null;
		try {
			ip = getIp();
		} catch (SocketException e) {
			e.printStackTrace();
		}
		if (ip == null) {
			WORKER_ID = (int) (Math.random() * SnowflakeIdUtils.MAX_WORKER_ID);
			log.error("生成机器编号失败,本机ip解析失败,ip:{}", ip);
			System.exit(500);
		} else {
			WORKER_ID = toWorkId(ip);
		}
	}

	private static final int WORKER_ID;

	public static int getWorkerId() {
		return WORKER_ID;
	}

	public static synchronized String getIp() throws SocketException {
		if (localIp != null) {
			return localIp;
		}
		// 本地IP,如果没有配置外网IP则返回它
		String localIp = null;
		// 外网IP
		String netIp = null;

		Enumeration<NetworkInterface> netInterfaces = NetworkInterface.getNetworkInterfaces();
		InetAddress ip;
		// 是否找到外网IP
		boolean find = false;
		while (netInterfaces.hasMoreElements() && !find) {
			NetworkInterface ni = netInterfaces.nextElement();
			Enumeration<InetAddress> address = ni.getInetAddresses();
			while (address.hasMoreElements()) {
				ip = address.nextElement();
				// 外网IP
				if (!ip.isSiteLocalAddress() && !ip.isLoopbackAddress()
						&& !ip.getHostAddress().contains(":")) {
					netIp = ip.getHostAddress();
					find = true;
					break;
				} else if (ip.isSiteLocalAddress() && !ip.isLoopbackAddress()
						&& !ip.getHostAddress().contains(":") && localIp == null) {
					localIp = ip.getHostAddress();
				}
			}
		}

		if (netIp != null && !"".equals(netIp)) {
			localIp = netIp;
			return netIp;
		} else {
			localIp = localIp;
			return localIp;
		}
	}

	static int toWorkId(String ip) {
		//1.获取本机ip
		//2.转换为数字
		String[] split = ip.split("\\.");
		if (split.length != 4) {
			log.error("生成机器编号失败,本机ip解析失败,ip:{}", ip);
			System.exit(500);
		} else {
			//3.按高低位拆成前后2部分
			//4.高低位再分高低位与或
			int high = (Integer.parseInt(split[0]) ^ Integer.parseInt(split[1]));
			int low = (Integer.parseInt(split[2]) << 8) + Integer.parseInt(split[3]);
			int workGroupMax = ~(-1 << workGroupIdBits);
			String groupId = System.getenv("SNOWFLAKE_GROUP_ID");
			if (groupId == null) {
				groupId = String.valueOf(high);
			}
			String snowflakeGroupIdStr = groupId.trim();
			int snowflakeGroupId = high;
			try {
				snowflakeGroupId = Integer.parseInt(snowflakeGroupIdStr);
			} catch (NumberFormatException e) {
				log.error("填写集群组id解析失败,{}", snowflakeGroupIdStr);
				System.exit(501);
			}
			//5.2部分分别按范围取模
			int workGroupId = snowflakeGroupId & workGroupMax;

			int moveBit = SnowflakeIdUtils.WORKER_ID_BITS - workGroupIdBits;

			int machineId = (((low & (-1 << 8))) & (~(-1 << moveBit))) + (low & (~(-1 << 8)));

			//6.组合生成机器id
			return (workGroupId << moveBit) + machineId;
		}
		return (int) (Math.random() * SnowflakeIdUtils.MAX_WORKER_ID);
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		log.info("根据当前机器ip:{} 生成机器码:{}", getIp(), getWorkerId());
	}
}

/**
 * 主引用与次引用都是long
 *
 * @author L.yn
 * @date 2021-07-19 10:34
 */
public class AtomicLongAndLong {

	private volatile long[] ref;
	protected static final Unsafe UNSAFE = reflectGetUnsafe();
	protected static final long REF_OFFSET =
			objectFieldOffset(UNSAFE, "ref", BaseAtomicPrimaryAndSecondaryReferences.class);

	public AtomicLongAndLong(long main, long minor) {
		this.ref = new long[]{main, minor};
	}

	public void setMain(long main) {
		set(main, ref[0]);
	}

	public void setMinor(long minor) {
		set(ref[0], minor);
	}

	public void set(long main, long minor) {
		if (main != ref[0] || minor != ref[1]) {
			ref = new long[]{main, minor};
		}
	}

	public long getMinor() {
		return ref[1];
	}

	public long getMain() {
		return ref[0];
	}

	public boolean compareAndSetMain(long expectedMain, long newMain) {
		return compareAndSet(expectedMain, newMain, ref[1], ref[1]);
	}

	public boolean compareAndSetMain(long expectedMain, long newMain, long newMinor) {
		long[] currentRef = this.ref;
		return expectedMain == currentRef[0]
				&& (newMain == currentRef[1]
				|| casSet(currentRef, new long[]{newMain, newMinor}));
	}


	public boolean compareAndSetMinor(long expectedMain, long expectedMinor, long newMinor) {
		return compareAndSet(expectedMain, expectedMain, expectedMinor, newMinor);
	}

	public boolean compareAndSetMinor(long expectedMinor, long newMinor) {
		return compareAndSet(ref[0], ref[0], expectedMinor, newMinor);
	}

	public boolean compareAndSet(long expectedMain, long newMain, long expectedMinor, long newMinor) {
		long[] currentRef = this.ref;
		return expectedMain == currentRef[0]
				&& expectedMinor == currentRef[1]
				&& ((newMain == currentRef[0]
				&& newMinor == currentRef[1])
				|| casSet(currentRef, new long[]{newMain, newMinor}));
	}


	public final long getAndDecrementMain() {
		return getAndAddMain(-1);
	}

	public final long decrementAndGetMain() {
		return addAndGetMain(-1);
	}

	public final long getAndIncrementMain() {
		return getAndAddMain(1);
	}

	public final long incrementAndGetMain() {
		return addAndGetMain(1);
	}

	public final long getAndAddMain(long add) {
		long currentMain, currentMinor;
		do {
			currentMain = getMain();
			currentMinor = getMinor();
		} while (!compareAndSetMain(currentMain, currentMain + add, currentMinor));
		return currentMain;
	}

	public final long addAndGetMain(long add) {
		return getAndAddMain(add) + add;
	}

	public final long getAndDecrementMinor() {
		return getAndAddMinor(-1);
	}

	public final long decrementAndGetMinor() {
		return addAndGetMinor(-1);
	}

	public final long getAndIncrementMinor() {
		return getAndAddMinor(1);
	}

	public final long incrementAndGetMinor() {
		return addAndGetMinor(1);
	}

	public final long getAndAddMinor(long add) {
		long currentMain, currentMinor;
		do {
			currentMain = getMain();
			currentMinor = getMinor();
		} while (!compareAndSetMinor(currentMain, currentMinor, currentMinor + add));
		return currentMinor;
	}

	public final long addAndGetMinor(long add) {
		return getAndAddMinor(add) + add;
	}


	private boolean casSet(long[] expectedRef, long[] newRef) {
		return UNSAFE.compareAndSwapObject(this, REF_OFFSET, expectedRef, newRef);
	}

	private static Unsafe reflectGetUnsafe() {
		try {
			Field field = Unsafe.class.getDeclaredField("theUnsafe");
			field.setAccessible(true);
			return (Unsafe) field.get(null);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	static long objectFieldOffset(Unsafe unsafe, String field, Class<?> clazz) {
		try {
			return unsafe.objectFieldOffset(clazz.getDeclaredField(field));
		} catch (NoSuchFieldException e) {
			// Convert Exception to corresponding Error
			NoSuchFieldError error = new NoSuchFieldError(field);
			error.initCause(e);
			throw error;
		}
	}
}

/**
 * 相互关联的原子操作类
 *
 * @param <MAIN>  主引用,更新时必须携带次引用一起更新
 * @param <MINOR> 次引用,可独立更新,无需更新主引用
 * @author L.yn
 * @date 2021-07-19 10:34
 */
public abstract class BaseAtomicPrimaryAndSecondaryReferences<MAIN, MINOR> {
	private volatile PrimaryAndSecondaryReferences<MAIN, MINOR> ref;
	protected static final Unsafe UNSAFE = reflectGetUnsafe();
	protected static final long REF_OFFSET =
			objectFieldOffset(UNSAFE, "ref", BaseAtomicPrimaryAndSecondaryReferences.class);

	public BaseAtomicPrimaryAndSecondaryReferences(MAIN main, MINOR minor) {
		this.ref = PrimaryAndSecondaryReferences.of(main, minor);
	}

	public void set(MAIN main, MINOR minor) {
		if (main != ref.main || minor != ref.minor) {
			ref = PrimaryAndSecondaryReferences.of(main, minor);
		}
	}

	public MINOR getMinor() {
		return ref.minor;
	}

	public MAIN getMain() {
		return ref.main;
	}

	public boolean compareAndSetMain(MAIN expectedMain, MAIN newMain, MINOR newMinor) {
		return compareAndSet(expectedMain, newMain, ref.minor, newMinor);
	}


	public boolean compareAndSetMinor(MAIN expectedMain, MINOR expectedMinor, MINOR newMinor) {
		return compareAndSet(expectedMain, expectedMain, expectedMinor, newMinor);
	}

	public boolean compareAndSet(MAIN expectedMain, MAIN newMain, MINOR expectedMinor, MINOR newMinor) {
		PrimaryAndSecondaryReferences<MAIN, MINOR> currentRef = this.ref;
		boolean b1 = expectedMain == currentRef.main
				&& expectedMinor == currentRef.minor;
		boolean b2 = newMain == currentRef.main
				&& newMinor == currentRef.minor;
		return b1 && (b2
				|| casSet(currentRef, PrimaryAndSecondaryReferences.of(newMain, newMinor)));
	}

	private boolean casSet(PrimaryAndSecondaryReferences<MAIN, MINOR> expectedRef, PrimaryAndSecondaryReferences<MAIN, MINOR> newRef) {
		return UNSAFE.compareAndSwapObject(this, REF_OFFSET, expectedRef, newRef);
	}

	private static Unsafe reflectGetUnsafe() {
		try {
			Field field = Unsafe.class.getDeclaredField("theUnsafe");
			field.setAccessible(true);
			return (Unsafe) field.get(null);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	static long objectFieldOffset(Unsafe unsafe, String field, Class<?> clazz) {
		try {
			return unsafe.objectFieldOffset(clazz.getDeclaredField(field));
		} catch (NoSuchFieldException e) {
			// Convert Exception to corresponding Error
			NoSuchFieldError error = new NoSuchFieldError(field);
			error.initCause(e);
			throw error;
		}
	}

	private static class PrimaryAndSecondaryReferences<MAIN, MINOR> {
		private volatile MAIN main;
		private volatile MINOR minor;

		private PrimaryAndSecondaryReferences(MAIN main, MINOR minor) {
			this.minor = minor;
			this.main = main;
		}

		static <MAIN, MINOR> PrimaryAndSecondaryReferences<MAIN, MINOR> of(MAIN main, MINOR minor) {
			return new PrimaryAndSecondaryReferences<>(main, minor);
		}

		@Override
		public String toString() {
			return "PrimaryAndSecondaryReferences{" + "main=" + main + ", minor=" + minor + '}';
		}
	}
}
/**
 * @author L.yn
 * @date 2021-07-19 10:34
 */
public class SnowflakeIdUtils {
	/**
	 * 参考时间戳
	 */
	public static final long REFERENCE_TIME;

	static {
		Calendar time = Calendar.getInstance();
		/*这里需要用想要的年份减去1900年,Date类就是这么规定的*/
		time.set(2010, Calendar.JANUARY, 1);
		REFERENCE_TIME = time.getTimeInMillis();
	}

	/**
	 * 机器回退容忍毫秒数
	 */
	public static final int FALLBACK_ACCEPT_MILLISECONDS = 100;
	/**
	 * 空闲位
	 */
	public static final int FREE_BITS = 1;
	/**
	 * 时间戳占据位数,不要修改
	 */
	public static final int TIMESTAMP_BITS = 41;
	/**
	 * 机器id所占的位数</br>
	 * 机器数量少时,生成效率不够可以改小一点</br>
	 * 推荐最少6位,最多12位
	 */
	public static final int WORKER_ID_BITS = 13;
	/**
	 * 序列在id中占的位数
	 */
	public static final int SERIAL_NUMBER_BITS = Long.SIZE - FREE_BITS - TIMESTAMP_BITS - WORKER_ID_BITS;
	/**
	 * 时间左移位数,固定值22
	 */
	public static final int TIMESTAMP_OFFSET = Long.SIZE - FREE_BITS - TIMESTAMP_BITS;
	/**
	 * 机器ID向左移位数
	 */
	public static final int WORKER_ID_OFFSET = Long.SIZE - FREE_BITS - TIMESTAMP_BITS - WORKER_ID_BITS;
	/**
	 * 自增序列向左移位数
	 */
	public static final int SERIAL_NUMBER_OFFSET =
			Long.SIZE - FREE_BITS - TIMESTAMP_BITS - WORKER_ID_BITS - SERIAL_NUMBER_BITS;
	/**
	 * 支持的最大数据机器id
	 */
	public static final int MAX_WORKER_ID = ~(-1 << WORKER_ID_BITS);
	/**
	 * 每毫秒自增最大数量
	 */
	public static final int SERIAL_NUMBER_MAX = ~(-1 << SERIAL_NUMBER_BITS);
	/**
	 * 上次生成ID的时间截+毫秒内序列
	 */
	private final AtomicLongAndLong lastTimestampAndSerialNumber = new AtomicLongAndLong(-1L, 0L);
	/**
	 * 工作机器ID
	 */
	@Getter
	private final int workerId;

	/**
	 * @param workerId 0~{@link SnowflakeIdUtils#MAX_WORKER_ID}
	 */
	public SnowflakeIdUtils(int workerId) {
		if (workerId > MAX_WORKER_ID || workerId < 0) {
			throw new IllegalArgumentException("workerId必须大于等于0小于等于" + MAX_WORKER_ID);
		}
		this.workerId = workerId;
	}

	/**
	 * 获得当前毫秒和毫秒内的自增序列
	 *
	 * @return [timestamp, serialNumber]
	 */
	public TimestampAndSerialNumber genTimestampAndSerialNumber() {
		long thisSerialNumber;
		//如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退
		long timestamp;
		long lastTime;
		for (; ; ) {
			lastTime = this.lastTimestampAndSerialNumber.getMain();
			timestamp = this.timeGen();
			while (timestamp < lastTime) {
				long backTime = lastTime - timestamp;
				//时钟回退很小
				if (backTime < FALLBACK_ACCEPT_MILLISECONDS) {
					try {
						Thread.sleep(backTime);
					} catch (InterruptedException ignored) {
					}
					if (this.timeGen() < this.lastTimestampAndSerialNumber.getMain()) {
						throw new RuntimeException("时钟多次回退");
					}
				} else {
					throw new RuntimeException("时钟回退,请重试");
				}
				lastTime = this.lastTimestampAndSerialNumber.getMain();
				timestamp = this.timeGen();
			}
			//如果是同一时间生成的,则获取当前递增数字
			if (lastTime == timestamp) {
				long minor = thisSerialNumber = this.lastTimestampAndSerialNumber.getMinor();
				if (!this.lastTimestampAndSerialNumber.compareAndSetMinor(timestamp, minor, minor + 1)) {
					//已经下一个毫秒了,重试
					continue;
				}
				//毫秒内序列溢出
				if (thisSerialNumber >= SERIAL_NUMBER_MAX) {
					//阻塞到下一个毫秒
					this.waitUntilTheNextMillis(lastTime);
					continue;
				}
				break;
			} else {
				//否则更新时间
				if (this.lastTimestampAndSerialNumber.compareAndSetMain(lastTime, timestamp, 1L)) {
					thisSerialNumber = 0L;
					break;
				}
			}
		}
		return new TimestampAndSerialNumber(timestamp, thisSerialNumber);
	}

	/**
	 * 生成下一个雪花ID
	 *
	 * @return 唯一雪花id
	 */
	public long genId() {
		TimestampAndSerialNumber timestampAndSerialNumber = this.genTimestampAndSerialNumber();
		return numbers2Long(timestampAndSerialNumber.getTimestamp() - REFERENCE_TIME, TIMESTAMP_OFFSET, this.workerId,
				WORKER_ID_OFFSET, timestampAndSerialNumber.getSerialNumber(), SERIAL_NUMBER_OFFSET);
	}

	/**
	 * 生成易识别的下一个雪花ID,目前会重复,不建议使用
	 *
	 * @return 唯一雪花id
	 */
	@Deprecated
	public long genFormatId() {
		TimestampAndSerialNumber t = this.genTimestampAndSerialNumber();
		long l = numbers2Long(t.getTimestamp(), TIMESTAMP_OFFSET, this.workerId, WORKER_ID_OFFSET, t.getSerialNumber(),
				SERIAL_NUMBER_OFFSET);
		return Long.parseLong(
				DateFormatUtils.format(new Date(t.timestamp), "yyMMddHHmm") + String.valueOf(l).substring(10, 19));
	}

	/**
	 * 生成易识别的下一个雪花ID,不会重复
	 *
	 * @return 唯一雪花id
	 */
	public String genFormatIdStr() {
		TimestampAndSerialNumber t = this.genTimestampAndSerialNumber();
		String l = String.valueOf(numbers2Long(this.workerId, WORKER_ID_OFFSET, t.getSerialNumber(),
				SERIAL_NUMBER_OFFSET));
		return DateFormatUtils.format(new Date(t.timestamp), "yyMMddHHmmssSSS") + StringUtils
				.repeat("0", 8 - l.length()) + l;
	}

	/**
	 * 拼接多个数字为一个数
	 *
	 * @return
	 */
	public static long numbers2Long(long number1, int offset1, long number2, int offset2) {
		return (number1 << offset1) | (number2 << offset2);
	}

	/**
	 * 拼接多个数字为一个数
	 *
	 * @return
	 */
	public static long numbers2Long(long number1, int offset1, long number2, int offset2, long number3, int offset3) {
		return ((number1 << offset1) | (number2 << offset2)) | (number3 << offset3);
	}

	/**
	 * 拼接多个数字为一个数
	 *
	 * @return
	 */
	public static long numbers2Long(long number1, int offset1, long number2, int offset2, long number3, int offset3,
									long number4, int offset4) {
		return (((number1 << offset1) | (number2 << offset2)) | (number3 << offset3)) | (number4 << offset4);
	}

	/**
	 * 阻塞到下一毫秒
	 *
	 * @param lastTimestamp 当前的毫秒数
	 */
	protected void waitUntilTheNextMillis(long lastTimestamp) {
		long timestamp = this.timeGen();
		for (int i = 0; timestamp == lastTimestamp; i++) {
			if (i > 10) {
				Thread.yield();
			}
			timestamp = this.timeGen();
		}
	}

	/**
	 * 返回当前时间
	 *
	 * @return 当前时间(毫秒)
	 */
	public long timeGen() {
		return System.currentTimeMillis();
	}

	int testGenId(boolean statisticalDuplication, int mode, int threadsNumber, long everyThreadGeneratedQuantity)
			throws InterruptedException {
		Thread[] threads = new Thread[threadsNumber];
		ConcurrentLinkedDeque<Object> list = new ConcurrentLinkedDeque<>();
		LongAdder count = new LongAdder();
		CountDownLatch latch = new CountDownLatch(threads.length + 1);
		Random random = new Random();
		ConcurrentSkipListSet<Integer> ids = new ConcurrentSkipListSet<>();
		Runnable runnable = () -> {
			int workerId;
			do {
				workerId = random.nextInt(MAX_WORKER_ID);
				if (!ids.contains(workerId)) {
					ids.add(workerId);
					break;
				}
			} while (true);
			SnowflakeIdUtils snowflakeIdUtils =
					//                this;
					new SnowflakeIdUtils(workerId);
			for (int i1 = 0; i1 < everyThreadGeneratedQuantity; i1++) {
				count.add(1);
				Object key;
				if (mode == 0) {
					key = snowflakeIdUtils.genId();
				} else if (mode == 1) {
					key = snowflakeIdUtils.genFormatId();
				} else {
					key = snowflakeIdUtils.genFormatIdStr();
				}
				if (statisticalDuplication) {
					list.add(key);
				}
			}
			latch.countDown();
		};
		Thread thread1 = new Thread(runnable);
		thread1.start();
		thread1.join();
		ids.clear();
		list.clear();
		count.reset();
		for (int i = 0; i < threads.length; i++) {
			threads[i] = new Thread(runnable, "gen-" + i);
		}
		long startTime = System.currentTimeMillis();
		for (Thread thread : threads) {
			thread.start();
		}
		latch.await();
		HashSet<Object> set = new HashSet<>(list.size() / 10);
		int res = 0;
		if (statisticalDuplication) {
			int num = 0;
			for (Object o : list) {
				if (set.contains(o)) {
					num++;
				} else {
					set.add(o);
				}
			}
			res += num;
		}
		return res;
	}

	static Map<String, Object> decode(long id) {
		HashMap<String, Object> res = new HashMap<>();
		long timestamp = (id >>> TIMESTAMP_OFFSET)
				& (((-1L << (Long.SIZE - TIMESTAMP_BITS))
				>>> (Long.SIZE - TIMESTAMP_BITS))
		);
		res.put("TIMESTAMP", timestamp + REFERENCE_TIME);
		res.put("TIMESTAMP_ORIGINAL", timestamp);
		res.put("DATA", new Date(timestamp + REFERENCE_TIME).toLocaleString());
		res.put("WORKER_ID", (((id >>> WORKER_ID_OFFSET)
				& (((-1L << (Long.SIZE - WORKER_ID_BITS))
				>>> (Long.SIZE - WORKER_ID_BITS))
		))));
		res.put("SERIAL_NUMBER", ((id >>> SERIAL_NUMBER_OFFSET)
				& (
				((-1L << (Long.SIZE - SERIAL_NUMBER_BITS))
						>>> (Long.SIZE - SERIAL_NUMBER_BITS))
		)
		));
		return res;
	}

	@Override
	public String toString() {
		return "SnowflakeIdUtils{"
				+ "workerId=" + this.workerId
				+ '}';
	}

	@Data
	public static class TimestampAndSerialNumber {
		private final long timestamp;
		private final long serialNumber;
	}
}

以实战来学习java,希望每个从我这边都有收获,有需要的同学加扣扣群:646410846,一起学习,共同进步~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
uuid是一种通用唯一标识符,通常由32位的16进制数字组成,它能够保证全球范围内的唯一性。然而,uuid也有一些弊端。首先,由于uuid的长度较长,当需要存储大量uuid时,会占用较多的空间。其次,uuid的生成算法通常是基于时间戳和随机数生成的,存在并发生成相同uuid的可能性。这会给分布式系统中的数据一致性带来挑战。另外,uuid的生成是一个计算密集型的过程,对服务器的性能要求较高。 为了解决uuid带来的问题,Twitter提出了雪花算法雪花算法是一种分布式唯一ID生成算法,它能够在分布式系统中生成唯一的、有序的、趋势递增的64位ID。雪花算法的结构如下: 1. 第1位是符号位,始终为0,表示正数。 2. 接下来的41位是时间戳,精确到毫秒级,可以使用69年。 3. 然后是10位的工作机器号,可以部署1024个节点。 4. 最后是12位的序列号,表示同一毫秒内的自增序号,支持每个节点每毫秒产生4096个ID。 雪花算法的优点在于,它是有序递增的,可以按照时间顺序排序。由于采用了时间戳和节点编号的组合作为ID的一部分,雪花算法能够保证在大部分场景下的唯一性和有序性。此外,雪花算法的生成速度非常快,不依赖于网络和外部资源。 总的来说,uuid的弊端主要在于长度长、并发生成相同uuid以及计算密集等方面,而雪花算法通过时间戳和节点编号的组合,能够解决uuid的一些问题,实现了分布式环境下的唯一ID生成。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北木楠-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值