分布式id生成——雪花算法

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicLong;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class IdGenerator {
	private static final Logger log = LoggerFactory.getLogger(IdGenerator.class);
	private static IdGenerator INSTANCE = new IdGenerator();
	private long machineId;

	private AtomicLong lastId;

	private long twepoch = 1561910400000L;   // 基准时间 2019-07-01 00:00:00

	private long machineIdBits = 10L;
	private long maxMachineId = -1L ^ (-1L << machineIdBits);
	
	private long sequenceBits = 10L;

	private long machineIdShift = sequenceBits;
	private long timestampLeftShift = sequenceBits + machineIdBits;
	private long maxSequence = (-1L ^ (-1L << sequenceBits)) - 1L;// 序列号的最大值
	private long sequenceMask = (-1L ^ (-1L << sequenceBits));
    
    private IdGenerator() {
		
	}
	
	public static IdGenerator getInstance() {
		return INSTANCE;
	}
	
	public void init(long machineId) {
		// sanity check for workerId
		if (machineId > maxMachineId || machineId < 0) {
			throw new IllegalArgumentException(
					String.format("machine Id can't be greater than %d or less than 0", maxMachineId));
		}
		log.info("ID generator starting. timestamp left shift " + timestampLeftShift + ", machine id bits "
				+ machineIdBits + ", sequence bits " + sequenceBits + ", machineId " + machineId);
		this.machineId = machineId;
		lastId = new AtomicLong((timeGen() - twepoch) << timestampLeftShift | randStartSequence());
	}
	
    private long randStartSequence() {
    	return ThreadLocalRandom.current().nextInt(10);
    }
    
    /**
     * 最高位固定为0
     * +------------------------+---------------------------+-----------------+
     * | 43bits timestamp in ms | 10bits worker(machine) ID | 10bits sequence |
     * +------------------------+---------------------------+-----------------+
     * @return
     */
	public long generateId() {
		while (true) {
			long now = timeGen();
			long oldId = lastId.get();
			long lastTimeInterval = oldId >>> timestampLeftShift;
			long nowInterval = now - twepoch;
			long sequence;

			if (nowInterval < lastTimeInterval) {
				Thread.yield();
				continue;
			} else if (nowInterval == lastTimeInterval) {
				sequence = oldId & sequenceMask;
				if (sequence >= maxSequence) {
					now = tillNextMillis(now);
					nowInterval = now - twepoch;
					sequence = randStartSequence();
				} else {
					sequence = sequence + 1;
				}
			} else {
				sequence = randStartSequence();
			}
			long newId = (nowInterval << timestampLeftShift) | (machineId << machineIdShift) | sequence;
			if (!lastId.compareAndSet(oldId, newId)) {
				Thread.yield();
				continue;
			}
			return newId;
		}
	}
	
	private long tillNextMillis(long lastTimestamp) {
		long timestamp = timeGen();
		while (timestamp <= lastTimestamp) {
			Thread.yield();
			timestamp = timeGen();
		}
		return timestamp;
	}

    private long timeGen(){
        return System.currentTimeMillis();
    }
}

带权重随机值生成器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

public class RandomValueGenerator {
	// [0][] value [1][] weight
	int[][] randomValueWeight;
	int randomWeightSum;
	
	
	/**
	 * 注意权重为0时
	 * @param randomValueWeight [0][]---value   [1][]---weight
	 * @return
	 */
	public boolean init(int[][] randomValueWeight) {
		if (randomValueWeight[0].length <= 0) {
			return false;
		}
		randomWeightSum = 0;
		List<int[]> randomValueWeightList = new ArrayList<>();
		for (int i = 0; i < randomValueWeight[0].length; ++i) {
			int randomWeight = randomValueWeight[1][i];
			if (randomWeight <= 0) {
				continue;
			}
			int randomValue = randomValueWeight[0][i];
			randomWeightSum += randomWeight;
			randomValueWeightList.add(new int[] {randomValue, randomWeightSum});
		}
		if (randomWeightSum == 0) {
			return false;
		}
		this.randomValueWeight = new int[2][randomValueWeightList.size()];
		for (int i = 0; i < randomValueWeightList.size(); i++) {
			int[] valueWeight = randomValueWeightList.get(i);
			this.randomValueWeight[0][i] = valueWeight[0];
			this.randomValueWeight[1][i] = valueWeight[1];
		}
		return true;
	}
	
	public int drawOnce() {
		if (randomValueWeight[0].length == 1) {
			return randomValueWeight[0][0];
		}
		int dice = ThreadLocalRandom.current().nextInt(randomWeightSum);
		return search(dice);
	}
	
	/**
	 * 二分查找
	 */
	private int search(int dice) {
		int low = 0;
		int high = randomValueWeight[0].length - 1;
		while (low <= high) {
			int mid = (low + high) / 2;
			if (dice == randomValueWeight[1][mid]) {
				return randomValueWeight[0][mid + 1];
			}
			if (dice < randomValueWeight[1][mid] && (mid == 0 || (mid > 0 && dice > randomValueWeight[1][mid - 1]))) {
				return randomValueWeight[0][mid];
			}
			if (dice < randomValueWeight[1][mid]) {
				high = mid - 1;
			}
			if (dice > randomValueWeight[1][mid]) {
				low = mid + 1;
			}
		}
		return -1;
	}
}

计算两个时间点之间间隔的天数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
	/**
	 * 计算两个时间点之间间隔的天数
	 * @param timemillis1
	 * @param timemillis2
	 * @return
	 */
	public static long calcDayDuration(long timemillis1, long timemillis2) {
		if (timemillis1 > timemillis2) {
			long tmp = timemillis1;
			timemillis1 = timemillis2;
			timemillis2 = tmp;
		}
		Calendar calendar1 = Calendar.getInstance();
		calendar1.setTimeInMillis(timemillis1);
		calendar1.set(Calendar.HOUR_OF_DAY, 0);
		calendar1.set(Calendar.MINUTE, 0);
		calendar1.set(Calendar.SECOND, 0);
		calendar1.set(Calendar.MILLISECOND, 0);
		return (timemillis2 - calendar1.getTimeInMillis()) / (24L * 3600L * 1000L) + 1;
	}

long和字节数组互转

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
	public static byte[] longToByteArray(long num) {
		byte[] ret = new byte[8];
		for (int i = 0; i < ret.length; i++) {
			ret[i] = (byte) (num & 0xff);// 将最低位保存在最低位
			num = num >> 8; // 向右移8位
		}
		return ret;
	}

	public static long byteArrayToLong(byte[] byteArray) {
		long ret = 0;
		for (int i = 0; i < byteArray.length; ++i) {
			ret |= ((long) byteArray[i]) << (8 * i) & 0xffl << (8 * i);
		}
		return ret;
	}