前面已经讲过了雪花算法,里面使用了System.currentTimeMillis()
获取时间,有一种说法是认为System.currentTimeMillis()
慢,是因为每次调用都会去跟系统打一次交道,在高并发情况下,大量并发的系统调用容易会影响性能(对它的调用甚至比new
一个普通对象都要耗时,毕竟new
产生的对象只是在Java
内存中的堆中)。我们可以看到它调用的是native
方法:
// 返回当前时间,以毫秒为单位。注意,虽然返回值的时间单位是毫秒,但值的粒度取决于底层操作系统,可能更大。例如,许多操作系统以数十毫秒为单位度量时间。
public static native long currentTimeMillis();
所以有人提议,用后台线程定时去更新时钟,并且是单例的,避免每次都与系统打交道,也避免了频繁的线程切换,这样或许可以提高效率。
这个优化成立么?
先上优化代码:
package snowflake;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
public class SystemClock {
private final int period;
private final AtomicLong now;
private static final SystemClock INSTANCE = new SystemClock(1);
private SystemClock(int period) {
this.period = period;
now = new AtomicLong(System.currentTimeMillis());
scheduleClockUpdating();
}
private void scheduleClockUpdating() {
ScheduledExecutorService scheduleService = Executors.newSingleThreadScheduledExecutor((r) -> {
Thread thread = new Thread(r);
thread.setDaemon(true);
return thread;
});
scheduleService.scheduleAtFixedRate(() -> {
now.set(System.currentTimeMillis());
}, 0, period, TimeUnit.MILLISECONDS);
}
private long get() {
return now.get();
}
public static long now() {
return INSTANCE.get();
}
}
只需要用SystemClock.now()
替换System.currentTimeMillis()
即可。
雪花算法SnowFlake
的代码也放在这里:
package snowflake;