一:线程不安全懒汉式(使用懒加载模式),当线程a,b同时调用getInstance方法,会创建两个线程对象
public class SingleTon{
// 静态实例变量
private static SingleTon instance;
// 私有化构造函数
private SingleTon(){
}
// 静态public方法,向整个应用提供单例获取方式
public static SingleTon getInstance(){
if(instance == null){
instance = new SingleTon();
}
return instance;
}
}
二:线程安全懒汉式(使用懒加载模式)
方案一、为了线程安全将整个getInstance()方法加上synchronized(会降低整个访问的速度,而且每次都要判断)
方案二、双重检验锁,先不同步,先检查实例是否存在,如果不存在才进入下面的同步块,这是第一重检查。进入同步块过后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。只需要同步一次,从而减少了多次在同步情况下进行判断所浪费的时间
使用关键字volatile,被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作主内存,从而确保多个线程能正确的处理该变量
public class SingleTon{
// 静态实例变量上加上volatile
private static volatile SingleTon instance;
// 私有化构造函数
private SingleTon(){
}
// 双重检查锁
public static SingleTon getInstance(){
if(instance == null){
synchronized(Singleton.class){
if(instance == null){
instance == new SingleTon();
}
}
}
return instance;
}
}
volatile简介:
volatile特性一:内存可见性,即线程A对volatile变量的修改,其他线程获取的volatile变量都是最新的
volatile特性二:可以禁止指令重排序(指令重排序:为了尽可能减少内存操作速度远慢于CPU运行速度所带来的CPU空置的影响,虚拟机会按照自己的一些规则将程序编写顺序打乱)
volatile不是保护线程安全的。它保护的是变量安全。主要的功能是保护变量不被主函数和中断函数反复修改造成读写错误
详见:https://blog.csdn.net/hang1995/article/details/80641948
Volatile和Synchronized四个不同点:
1 粒度不同,Volatile针对变量 ,Synchronized锁对象和类
2 volatile线程不阻塞,syn线程阻塞
3 volatile不保证原子性(i++不是原子性)(例外,虚拟机允许对64位数据类型(long和double),分为2次32为的操作来处理,但是最新JDK还是实现了原子操作),syn保证三大特性(原子性,可见性,有序性)
4 volatile没有优化,syn经过编译器优化
三:饿汉式,尚未需要用到此单一实例的时候就先实例化
public class SingleTon{
// 静态实例变量,直接初始化
private static SingleTon instance = new SingleTon();
// 私有化构造函数
private SingleTon(){
}
// 静态public方法,向整个应用提供单例获取方式
public static SingleTon getInstance(){
return instance;
}
}