package Lesson4;
//面试 线程安全
//单例
public class SingleTon {
//返回单例实例 饿汉模式
private SingleTon(){
//一定要写出来,不能在外部new对象 写成private
}
//饿汉模式
private static final SingleTon SINGTON=new SingleTon();
public static SingleTon getInstance(){
return SINGTON;
}
//懒汉模式
private static volatile SingleTon SINGTON2=null;
public static SingleTon getInstance2(){
//开始判断就不安全了,两个线程都会实例化,返回不同的对象
if(SINGTON2==null){
//多个线程可以同时进入这行判断代码判断,都判断为null
SINGTON2=new SingleTon();
}
return SINGTON2;
}
//多线程的话有可见性问题,第二个线程判断是否为null,可能已经不为null了
//保证线程安全性
public synchronized static SingleTon getInstance3(){
//开始判断就不安全了,两个线程都会实例化,返回不同的对象
if(SINGTON2==null){
//多个线程可以同时进入这行判断代码判断,都判断为null
SINGTON2=new SingleTon();
}
return SINGTON2;
}
public static SingleTon getInstance4(){
if(SINGTON2==null){
//加volatile从主内存中读
synchronized (SingleTon.class){
//这块代码块的原子性
/*可以分解成三步操作
1.分配对象内存空间
2.执行对象初始化
3.把对象给引用
4.可能重排序132,3在2之前执行了,就返回了,这样对象还可能为空
*/
//volatile禁止重排序 所以给SINGTON2加上volatile
//第一个线程可能没赋上值
if(SINGTON2==null){
//写
SINGTON2=new SingleTon();
}
//synchronized 写 保证安全性 不保证有序性,所以结合
//volatile读 保证可见性 不保证原子性,从主内存对最新的
//如果写操作是一个原子操作的话,能用volatile
//不是的话,还要加上synchronized
//只要不是操作系统上的原子性,要用volatile防止顺序变换
return SINGTON2;
}
}
return SINGTON2;
}
}