public class Singleton {
private volatile static Singleton uniqueSingleton;
private Singleton() {
}
public Singleton getInstance() {
if (null == uniqueSingleton) {
synchronized (Singleton.class) {
if (null == uniqueSingleton) {
uniqueSingleton = new Singleton();
}
}
}
return uniqueSingleton;
}
}
1 单例模式 何时懒汉 何时饿汉
懒汉 延迟加载 一些很耗资源的(时间 io cpu 内存)操作 可以用到时 加载 初始化
饿汉 简单的实现 可以保证线程安全的单例
2 去掉 volatile 怎样
A a=new A();
一行代码 其实翻译成机器码(可以理解成 汇编码)其实是多个指令
至少两步
一 分配内存 初始化
二 内存地址和引用 关联 (栈 存 引用;堆 存 实例化的对象)
这两步其实 是无序的
如果 第一个线程 进去 第一个判空 为空 去new 但是 先走了第二步 停下 此时 第二个线程 进去 就会 直接
return uniqueSingleton; 一个未初始化完成的对象 去用可能就会有问题 比如 里面有对象 啥的 空指针
//volatile vs synchronized
volatile 保证多线程下 可见性 有序性 但不保证原子性
jdk 一直在对锁优化 所以 volatile 不一定比 synchronized 快多少 但是多少会快
首先 实现的机制不一样 synchronized 基于 锁的互斥 而且 volatile 没保证原子性 多少会快
// 扩展 : 什么时候用 volatile
不存在原子性 或者 不需要保证原子性
比如 一写多读
注意 jdk 1.5 及之后 才保证有序
3 synchronized 参考:https://blog.csdn.net/zjy15203167987/article/details/82531772
一个对象只有一把锁,一个线程获取了该对象的锁之后,其他线程无法获取该对象的锁,就不能访问该对象的其他synchronized实例方法,但是可以访问非synchronized修饰的方法(待验证)
修饰代码块 相对修饰方法的好处 修饰代码块 锁的东西更少 效率相对较高
修饰非static方法和修饰代码块 一样 其实锁的也是对象
代码块锁对象的三种方式(待验证 : A类中的代码块 怎么去锁B对象 B类)
①
class A{
static A a=new A();
synchronized(a){
}
}
②
synchronized(this){ }
③(待研究 锁的是 对象 还是类)
synchronized(A.class){
}
4 为啥不直接
synchronized 修饰方法
慢 因为只有第一次才需要锁
后面new 后 不需要锁 直接return