赞
踩
import com.ruoyi.project.mooc.domain.MoocSchoolRecord; import com.ruoyi.project.mooc.domain.MoocStudyPlanStudent; import com.ruoyi.project.mooc.domain.MoocStudyPlanStudentCourse; import org.apache.commons.lang3.RandomUtils; import org.apache.commons.lang3.StringUtils; import java.net.Inet4Address; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.UnknownHostException; import java.util.*; import java.util.stream.Collectors; /** * <p>名称:IdWorker.java</p> * <p>描述:分布式自增长ID</p> * <pre> * Twitter的 Snowflake JAVA实现方案 * </pre> * 核心代码为其IdWorker这个类实现,其原理结构如下,我分别用一个0表示一位,用—分割开部分的作用: * 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000 * 在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间, * 然后5位datacenter标识位,5位机器ID(并不算标识符,实际是为线程标识), * 然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。 * 这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和机器ID作区分), * 并且效率较高,经测试,snowflake每秒能够产生26万ID左右,完全满足需要。 * <p> * 64位ID (42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加)) * * @author Polim */ public class IdWorker { public static Long mac; public static Long ip; /** * 开始时间截 (2015-01-01) */ private final static long twepoch = 1420041600000L; /** * 机器id所占的位数 */ private final static long workerIdBits = 5L; /** * 数据标识id所占的位数 */ private final static long datacenterIdBits = 5L; /** * 序列在id中占的位数 */ private final static long sequenceBits = 12L; /** * 机器ID向左移12位 */ private final static long workerIdShift = sequenceBits; /** * 数据标识id向左移17位(12+5) */ private final static long datacenterIdShift = sequenceBits + workerIdBits; /** * 时间截向左移22位(5+5+12) */ private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; /** * 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) */ private final static long sequenceMask = -1L ^ (-1L << sequenceBits); /** * 毫秒内序列(0~4095) */ private static long sequence = 0L; /** * 上次生成ID的时间截 */ private static long lastTimestamp = -1L; /** * 获得下一个ID (该方法是线程安全的) * * @return SnowflakeId */ private static synchronized long 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; if (mac == null) { mac = getMac(); } if (ip == null) { ip = getIp(); } // 移位并通过或运算拼到一起组成64位的ID return ((timestamp - twepoch) << timestampLeftShift) // | (mac << datacenterIdShift) // | (ip << workerIdShift) // | sequence; } /** * 阻塞到下一个毫秒,直到获得新的时间戳 * * @param lastTimestamp 上次生成ID的时间截 * @return 当前时间戳 */ protected static long tilNextMillis(long lastTimestamp) { long timestamp = timeGen(); while (timestamp <= lastTimestamp) { timestamp = timeGen(); } return timestamp; } /** * 返回以毫秒为单位的当前时间 * * @return 当前时间(毫秒) */ protected static long timeGen() { return System.currentTimeMillis(); } public static Long getMac() { InetAddress adress = null; try { adress = InetAddress.getLocalHost(); NetworkInterface net = NetworkInterface.getByInetAddress(adress); byte[] macBytes = net.getHardwareAddress(); int sum = 0; for (int b : macBytes) { sum += Math.abs(b); } return (long) (sum % 32); } catch (Exception e) { e.printStackTrace(); return RandomUtils.nextLong(0, 31); } } public static Long getIp() { try { String hostAddress = Inet4Address.getLocalHost().getHostAddress(); int[] ints = StringUtils.toCodePoints(hostAddress); int sums = 0; for (int b : ints) { sums += b; } return (long) (sums % 32); } catch (UnknownHostException e) { e.printStackTrace(); // 如果获取失败,则使用随机数备用 return RandomUtils.nextLong(0, 31); } } public static String getNextId() { return nextId() + String.format("%02d", System.nanoTime() % 100); } public static Long workerId() { long nextId = nextId(); return nextId; } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。