百万秒级Id随机生成器不重复

package com.careye.common.base;

import com.careye.common.tool.IDManager;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;

/**
 * ID 产生器
 *
 * @author xuxiaoke
 *
 */
public class IDCreator {

	// ==============================Fields===========================================
	/** 开始时间截 (2015-01-01) */
	private final long twepoch = 1420041600000L;

	/** 机器id所占的位数 */
	private final long workerIdBits = 5L;

	/** 数据标识id所占的位数 */
	private final long datacenterIdBits = 5L;

	/** 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */
	private final long maxWorkerId = -1L ^ (-1L << workerIdBits);

	/** 支持的最大数据标识id,结果是31 */
	private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);

	/** 序列在id中占的位数 */
	private final long sequenceBits = 12L;

	/** 机器ID向左移12位 */
	private final long workerIdShift = sequenceBits;

	/** 数据标识id向左移17位(12+5) */
	private final long datacenterIdShift = sequenceBits + workerIdBits;

	/** 时间截向左移22位(5+5+12) */
	private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;

	/** 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) */
	private final long sequenceMask = -1L ^ (-1L << sequenceBits);

	/** 工作机器ID(0~31) */
	private long workerId;

	/** 数据中心ID(0~31) */
	private long datacenterId;

	/** 毫秒内序列(0~4095) */
	private long sequence = 0L;

	/** 上次生成ID的时间截 */
	private long lastTimestamp = -1L;

	// ==============================Constructors=====================================
	/**
	 * 构造函数
	 *
	 * @param workerId
	 *            工作ID (0~31)
	 * @param datacenterId
	 *            数据中心ID (0~31)
	 */
	public IDCreator(long workerId, long datacenterId) {
		if (workerId > maxWorkerId || workerId < 0) {
			throw new IllegalArgumentException(
					String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
		}
		if (datacenterId > maxDatacenterId || datacenterId < 0) {
			throw new IllegalArgumentException(
					String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
		}
		this.workerId = workerId;
		this.datacenterId = datacenterId;
	}


	/**
	 * 构造函数
	 *
	 * @param workerId
	 *            工作ID (0~31)
	 * @param datacenterId
	 *            数据中心ID (0~31)
	 */
	public IDCreator() {
		this.workerId = 0;
		this.datacenterId = 1;
	}

	// ==============================Methods==========================================
	/**
	 * 获得下一个ID (该方法是线程安全的)
	 *
	 * @return SnowflakeId
	 */
	public synchronized String nextId() {
		long timestamp = timeGen();

		// 如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
		if (timestamp < lastTimestamp) {
			throw new RuntimeException(String.format(
					"Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
		}

		// 如果是同一时间生成的,则进行毫秒内序列
		if (lastTimestamp == timestamp) {
			sequence = (sequence + 1) & sequenceMask;
			// 毫秒内序列溢出
			if (sequence == 0) {
				// 阻塞到下一个毫秒,获得新的时间戳
				timestamp = tilNextMillis(lastTimestamp);
			}
		}
		// 时间戳改变,毫秒内序列重置
		else {
			sequence = 0L;
		}

		// 上次生成ID的时间截
		lastTimestamp = timestamp;

		// 移位并通过或运算拼到一起组成64位的ID
		long id = ((timestamp - twepoch) << timestampLeftShift) //
				| (datacenterId << datacenterIdShift) //
				| (workerId << workerIdShift) //
				| sequence;

		return id+"";
	}

	/**
	 * 阻塞到下一个毫秒,直到获得新的时间戳
	 *
	 * @param lastTimestamp
	 *            上次生成ID的时间截
	 * @return 当前时间戳
	 */
	protected long tilNextMillis(long lastTimestamp) {
		long timestamp = timeGen();
		while (timestamp <= lastTimestamp) {
			timestamp = timeGen();
		}
		return timestamp;
	}

	/**
	 * 返回以毫秒为单位的当前时间
	 *
	 * @return 当前时间(毫秒)
	 */
	protected long timeGen() {
		return System.currentTimeMillis();
	}

	public long getDatacenterId() {
		return datacenterId;
	}

	public long getWorkerId() {
		return workerId;
	}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要生成15位不重复ID,有几种方法可以考虑: 1. 使用 UUID(通用唯一识别码)。UUID 是一种由算法生成的 128 位数字,可以确保全球范围内的唯一性。使用 UUID 生成 15 位 ID 的方法是,将 UUID 的前 15 位作为 ID。 2. 使用当前时间戳。可以使用当前的时间戳(以毫秒为单位)作为 ID,并将其转换为字符串。这样生成的 ID 就是当前时间的字符串表示,且因为每一毫秒内只有一个时间戳,所以这样生成的 ID 也是唯一的。 3. 使用随机数。可以使用随机数生成生成一个 15 位的随机数,然后将其转换为字符串。这样生成的 ID 就是一个随机字符串,具有很高的唯一性。 4. 使用数据库自增长 ID。如果你使用数据库存储数据,那么可以使用数据库的自增长 ID 作为 ID。自增长 ID 每次都会增加 1,所以可以保证每一个 ID 都是唯一的。 无论使用哪种方法生成 ID,都可以确保生成的 ID 是唯一的。 ### 回答2: 生成15位不重复ID有以下几种方式: 1. 时间戳+随机数:使用当前时间戳作为ID的前10位,再加上5位随机数。由于时间戳每微秒都在变化,所以基本上保证了不重复性。 2. 哈希算法:将某个具有唯一性的信息(如用户名、邮箱等)通过哈希算法转换为固定长度的字符串。可以使用MD5、SHA1等哈希算法,在其输出中截取15位。 3. 自增序列+随机数:设定一个全局自增序列,每生成一个ID时,序列自增1,再在序列的基础上加上5位随机数。 4. UUID:使用通用唯一识别码(Universally Unique Identifier,UUID),该标识符可以在系统中保证唯一性。通常,UUID是一个32位的16进制数,可以通过简单的编码转换获取到15位。 需要注意的是,以上方法并不能完全保证生成的ID绝对不重复,但可以大大降低重复的概率。另外,如果需要生成更为复杂的唯一ID,可以结合不同的方法或使用更长的位数来增加唯一性。 ### 回答3: 生成15位不重复ID可以考虑以下方法: 1. 使用时间戳:将当前时间转换为一个15位的数字作为ID。但是需要注意在同一毫秒内生成的ID可能会重复,因此需要加入一些额外的判断和处理机制。 2. 使用UUID算法:UUID(Universally Unique Identifier)是一种标识符,可以生成一个128位的字符串,可以使用其中的一部分作为15位的ID。例如,可以计算UUID的哈希值,并截取合适长度的子串作为ID。 3. 使用自增序列:可以维护一个长期增长且不重复的序列,每次生成ID时递增该序列的值,并将其转换为15位数字作为ID。需要注意并发操作时可能存在竞争和重复的问题。 4. 综合考虑:可以结合以上方法,例如使用时间戳与随机数相结合,或者将UUID的哈希值与自增序列进行组合,以确保生成的ID重复且具有一定的随机性。 无论使用哪种方法,都需要考虑多方面的因素,如运行环境、并发操作、安全性等。在实际应用中,可以根据具体需求和使用场景选择适合的方法生成不重复的15位ID
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值