目录
最终解决方案
双重检查加锁
首先检查是否实例已经创建了,如果尚未创建,才进行同步。这样一来,只有第一次会同步
public class SnowFlakeGenerateIDUtils {
public volatile static SnowFlakeGenerateIDUtils snowWork = null;
public static String getSnowId() {
//单例,解决并发问题
if (snowWork == null) {
synchronized (SnowFlakeGenerateIDUtils.class) {
if (snowWork == null) {
snowWork = new SnowFlakeGenerateIDUtils(currentWorkerId, currentDatacenterId, currentSequence);
}
}
}
Long nextId = snowWork.nextId();
return nextId.toString();
}
}
注意的点:
- 对象需要用volatile关键字修饰
- 锁用的是单例对象 synchronized (SnowFlakeGenerateIDUtils.class)
探讨为何这么写?
先来看一段代码
private Singleton() {}
public static Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
这段逻辑,在单线程的程序中工作得很好。但是,当引入多线程时,就可能会出现问题。
个人理解:当一个线程正在执行对象初始化,同事另一个对象也进来,发现对象并没有初始化,也执行初始化。就会存在并发下被覆盖的问题。
引出Volatile
Volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的“可见性”。可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。则上面对象初始化操作针对不同线程不可见的问题就解决了。
除了这种解决方式,当然还有其他的,可参考:
https://blog.csdn.net/qq_36704549/article/details/104521878