package main
import (
"fmt"
"sync"
"time"
)
type MySnowFlakeWorker struct {
MachineID int64 // 机器 id 占10位, 十进制范围是 [ 0, 1023 ]
Sn int64 // 序列号占 12 位,十进制范围是 [ 0, 4095 ]
LastTimeStamp int64 // 上次的时间戳(毫秒级), 1秒=1000毫秒, 1毫秒=1000微秒,1微秒=1000纳秒
Lock sync.Mutex // 加锁保证唯一性
}
func (p *MySnowFlakeWorker) init() {
p.LastTimeStamp = time.Now().UnixNano() / 1000000
}
func (p *MySnowFlakeWorker) SetMachineId(mid int64) {
// 把机器 id 左移 12 位,让出 12 位空间给序列号使用
p.MachineID = mid << 12
}
func (p *MySnowFlakeWorker) GenerateId() int64 {
// 加锁/解锁
p.Lock.Lock()
defer p.Lock.Unlock()
curTimeStamp := time.Now().UnixNano() / 1000000
// 同一毫秒
if curTimeStamp == p.LastTimeStamp {
p.Sn++
// 序列号占 12 位,十进制范围是 [ 0, 4095 ]
if p.Sn > 4095 {
time.Sleep(time.Millisecond)
curTimeStamp = time.Now().UnixNano() / 1000000
p.LastTimeStamp = curTimeStamp
p.Sn = 0
}
// 取 64 位的二进制数 0000000000 0000000000 0000000000 0001111111111 1111111111 1111111111 1 ( 这里共 41 个 1 )和时间戳进行并操作
// 并结果( 右数 )第 42 位必然是 0, 低 41 位也就是时间戳的低 41 位
rightBinValue := curTimeStamp & 0x1FFFFFFFFFF
// 机器 id 占用10位空间,序列号占用12位空间,所以左移 22 位; 经过上面的并操作,左移后的第 1 位,必然是 0
rightBinValue <<= 22
id := rightBinValue | p.MachineID | p.Sn
return id
}
if curTimeStamp > p.LastTimeStamp {
p.Sn = 0
p.LastTimeStamp = curTimeStamp
// 取 64 位的二进制数 0000000000 0000000000 0000000000 0001111111111 1111111111 1111111111 1 ( 这里共 41 个 1 )和时间戳进行并操作
// 并结果( 右数 )第 42 位必然是 0, 低 41 位也就是时间戳的低 41 位
rightBinValue := curTimeStamp & 0x1FFFFFFFFFF
// 机器 id 占用10位空间,序列号占用12位空间,所以左移 22 位; 经过上面的并操作,左移后的第 1 位,必然是 0
rightBinValue <<= 22
id := rightBinValue | p.MachineID | p.Sn
return id
}
if curTimeStamp < p.LastTimeStamp {
return 0
}
return 0
}
func main() {
snowFlake := &MySnowFlakeWorker{}
snowFlake.init()
snowFlake.SetMachineId(93126)
for i := 0; i < 10; i++ {
id := snowFlake.GenerateId()
fmt.Println("生成id:", id)
}
}
直接运行:
main()即可