1、饿汉模式
public class Singletan {
private static Singletan instance = new Singletan();
public Singletan(){}
public static Singletan getInstance() {
return instance;
}
}
2、静态内部类
较上面有所优化,就是使用了lazy-loading。Singletan类被加载,但是instance并没有立即初始化,只有调用getInstance方法时才会初始化。
//加载内部类SingletanHolder,从而实例化instance
public class Singletan {
private static class SingletanHolder {
private static final Singletan INSTANCE = new Singletan();
}
public Singletan(){}
public static final Singletan getInstance() {
return SingletanHolder.INSTANCE;
}
}
3、CAS:Compare and Swap(比较和交换)
- 乐观锁,无锁算法。CAS有3个参数:内存值V、旧值A、要修改的新值B,当且仅当旧值 A 和内存值 V 相同时,才将内存值 V 修改为 B,否则会尝试重新获取 V 的当前值,重新比较。
- 优点:没有线程切换和阻塞的额外开销,支持较大并行度。
- 缺点:①在并发量较高时,如果许多线程反复尝试去更新一个变量,却又一直更新失败,会消耗很多CPU资源。②银行取款 ABA 问题,所以不仅要比较旧值和内存值,还要比较变量的版本号是否一致,只有一致才进行操作。
银行取款ABA问题:假如账户开始有100元,在取款机上取走50,取款机出现问题一共提交了两次请求(线程1,线程2),第二次请求(线程2)在执行时因为某种原因被阻塞了,这时候有人往你的账户打了50元,线程2恢复了可执行状态,这个时候就会出现问题,原本线程2应该执行失败的,但是比较后仍然与旧值一致,这样就造成了账户实际上扣款了两次!