Java性能问题有关操作员或



这是一种雪花算法。我一个人实施。使用生成生成唯一ID。

// start time
private final long startTimestamp = ZonedDateTime.of(2015, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()).toInstant().toEpochMilli();
// shift value
private final long workerDataLeftShiftValue;
// mask
private final long sequenceMask = 4095L;
// sequence from  0 - 4095
private long sequence = 0;
// last timestamp
private long lastTimestamp = System.currentTimeMillis();
public Snowflake(int dataCenterId, int workerId) {
    // shifts
    int workerLeftShift = 12;
    int dataCenterLeftShift = 17;
    this.workerDataLeftShiftValue = workerId << workerLeftShift | dataCenterId << dataCenterLeftShift;
    // max id
    int maxId = 32;
    if (!(dataCenterId < maxId) || !(workerId < maxId)) {
        throw new IllegalStateException("not a valid id, snowflake is not working");
    }
}
@Override
public synchronized long generate() {
    long curTimestamp = System.currentTimeMillis();
    if (lastTimestamp > curTimestamp) {
        throw new IllegalStateException("last timestamp > current timestamp, clock error when using snowflake");
    }
    if (lastTimestamp == curTimestamp) {
        sequence = (sequence + 1) & sequenceMask;
        if (sequence == 0) {
            while (curTimestamp == System.currentTimeMillis()) {
                curTimestamp = System.currentTimeMillis();
            }
        }
    } else {
        sequence = 0;
    }
    lastTimestamp = curTimestamp;
    return sequence | workerDataLeftShiftValue | (curTimestamp - startTimestamp) << 22L;
}
public static void main(String[] args) {
    Snowflake snowflake = new Snowflake(1, 1);
    System.out.println(snowflake.generate());
}

这是Twitter实施的雪花。使用NextID生成唯一的ID。

private final long twepoch = 1420041600000L;
private final long workerIdBits = 5L;
private final long datacenterIdBits = 5L;
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
private final long sequenceBits = 12L;
private final long workerIdShift = sequenceBits;
private final long datacenterIdShift = sequenceBits + workerIdBits;
private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
private long workerId;
private long datacenterId;
private long sequence = 0L;
private long lastTimestamp = -1L;
public SnowflakeTwitter(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;
}
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) {
        sequence = (sequence + 1) & sequenceMask;
        if (sequence == 0) {
            timestamp = tilNextMillis(lastTimestamp);
        }
    }
    else {
        sequence = 0L;
    }
    lastTimestamp = timestamp;
    return ((timestamp - twepoch) << timestampLeftShift) //
            | (datacenterId << datacenterIdShift) //
            | (workerId << workerIdShift) //
            | sequence;
}
protected long tilNextMillis(long lastTimestamp) {
    long timestamp = timeGen();
    while (timestamp <= lastTimestamp) {
        timestamp = timeGen();
    }
    return timestamp;
}
protected long timeGen() {
    return System.currentTimeMillis();
}
public static void main(String[] args) {
    SnowflakeTwitter idWorker = new SnowflakeTwitter(0, 0);
    System.out.println(idWorker.nextId());
}

所以我对它们进行了一些测试性能。使用10个线程生成ID。1个线程观看ID的总数。

public static void main(String[] args) throws InterruptedException {
    Snowflake snowflake = new Snowflake(1, 1);
    SnowflakeTwitter snowflakeTwitter = new SnowflakeTwitter(1, 1);
    AtomicInteger sf = new AtomicInteger(0);
    AtomicInteger sft = new AtomicInteger(0);
    int tSize = 10;
    for (int i = 0; i < tSize; i++) {
        new Thread(() -> {
            while (true) {
                snowflakeTwitter.nextId();
                sft.incrementAndGet();
            }
        }).start();
        new Thread(() -> {
            while (true) {
                snowflake.generate();
                sf.incrementAndGet();
            }
        }).start();
    }
    new Thread(() -> {
        while (true) {
            System.out.println("sft: " + sft.get() + ", sf: " + sf.get());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }).start();
    TimeUnit.SECONDS.sleep(100);
}

结果是: sft: 6752, sf: 5663 sft: 477792, sf: 194125 sft: 1279909, sf: 661183 sft: 2320410, sf: 1206993 sft: 3374425, sf: 1712642 sft: 4255803, sf: 2157003 sft: 4661517, sf: 2338219 sft: 5115752, sf: 2551146

所以我的隐含速度很慢。我发现原因是: // my impl return sequence | workerDataLeftShiftValue | (curTimestamp - startTimestamp) << 22L; // twitter impl return ((timestamp - twepoch) << timestampLeftShift) // | (datacenterId << datacenterIdShift) // | (workerId << workerIdShift) // | sequence; 为什么引起速度差?谢谢。

明显(如1 xor x == 〜x,其中 ~是一个人的补充,位否定):

-1L ^ x

只是

~x

然后可以使班次使用常数,最终int。

final int workerLeftShift = 12;
final int dataCenterLeftShift = 17;

我没有检查生成的代码,但这似乎与您提到的表达式有关。

最新更新