- 雪花算法snowflake介绍以及单例模封装
- 雪花算法的由来
- 雪花算法的结构
- 组成
- 作用
- 结合静态单例模式的实现
- Twitter使用scala语言开源了一种分布式 id 生成算法——SnowFlake算法,被翻译成了雪花算法。
- 雪花属于六方晶系,它具有四个结晶轴,其中三个辅轴在一个基面上,互相以60度的角度相交,第四轴(主晶轴)与三个辅轴所形成的基面垂直.
- 雪花的基本形状是六角形,但是大自然中却几乎找不出两朵完全相同的雪花,每一个雪花都拥有自己的独有图案,就象地球上找不出两个完全相同的人一样。许多学者用显微镜观测过成千上万朵雪花,这些研究最后表明,形状、大小完全一样和各部分完全对称的雪花,在自然界中是无法形成的
雪花算法生成的ID是一个64 bit的long型的数字且按时间趋势递增。大致由首位无效符、时间戳差值、机器编码,序列号四部分组成。
雪花算法可以保证:
- 生成的所有的id都是随着时间递增
- 分布式系统内不会产生重复的id(因为有机器位做区分)
结合静态单例模式的实现所以雪花算法可以作为我们生成数据库主键id 甚至是在某些情况下生成唯一序列码的首要选择之一
import java.lang.management.ManagementFactory; import java.net.InetAddress; import java.net.NetworkInterface; public class IdWorker { private final static long START = 1288834974657L; private final static long WORKER_ID_BITS = 5L; private final static long DATACENTER_ID_BITS = 5L; private final static long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS); private final static long MAX_DATACENTER_ID = ~(-1L << DATACENTER_ID_BITS); private final static long SEQUENCE_BITS = 12L; private final static long WORKER_ID_SHIFT = SEQUENCE_BITS; private final static long DATACENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS; private final static long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATACENTER_ID_BITS; private final static long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS); private static long lastTimestamp = -1L; private long sequence = 0L; private final long workerId; private final long datacenterId; private final static IdWorker ID_WORKER = new IdWorker(); private IdWorker(){ this.datacenterId = getDatacenterId(); this.workerId = getMaxWorkerId(datacenterId); } public static IdWorker getInstance(){ return ID_WORKER; } public synchronized long nextId() { long timestamp = timeGen(); if (timestamp < lastTimestamp) { throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp)); } if (lastTimestamp == timestamp) { // 当前毫秒内,则+1 sequence = (sequence + 1) & SEQUENCE_MASK; if (sequence == 0) { // 当前毫秒内计数满了,则等待下一秒 timestamp = tilNextMillis(lastTimestamp); } } else { sequence = 0L; } lastTimestamp = timestamp; // ID偏移组合生成最终的ID,并返回ID return ((timestamp - START) << TIMESTAMP_LEFT_SHIFT) | (datacenterId << DATACENTER_ID_SHIFT) | (workerId << WORKER_ID_SHIFT) | sequence; } private long tilNextMillis(final long lastTimestamp) { long timestamp = this.timeGen(); while (timestamp <= lastTimestamp) { timestamp = this.timeGen(); } return timestamp; } private long timeGen() { return System.currentTimeMillis(); } protected static long getMaxWorkerId(long datacenterId) { StringBuilder mid = new StringBuilder(); mid.append(datacenterId); String name = ManagementFactory.getRuntimeMXBean().getName(); if (!name.isEmpty()) { mid.append(name.split("@")[0]); } return (mid.toString().hashCode() & 0xffff) % (IdWorker.MAX_WORKER_ID + 1); } protected static long getDatacenterId() { long id = 0L; try { InetAddress ip = InetAddress.getLocalHost(); NetworkInterface network = NetworkInterface.getByInetAddress(ip); if (network == null) { id = 1L; } else { byte[] mac = network.getHardwareAddress(); id = ((0x000000FF & (long) mac[mac.length - 1]) | (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6; id = id % (IdWorker.MAX_DATACENTER_ID + 1); } } catch (Exception e) { System.out.println(" getDatacenterId: " + e.getMessage()); } return id; } }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)