徐无忌并发编程笔记:案例实战:线程安全的单例模式几种实现方式?
完成:第一遍
1.线程安全的单例模式有几种实现方式?
方式一:懒汉式加载
懒汉式单例
1.线程安全
2.采用同步方法
当使用时才创建instance
优点:起到lazy loading的效果,线程安全,synchronized同步方法同一时间只会有一个线程进入
缺点:加锁,效率低,并发情况下,每个线程在获取实例时都需要进行同步
package code01;
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton(){
}
public static synchronized LazySingleton getInstance(){
if(instance == null){
instance = new LazySingleton();
}
return instance;
}
}
方式二:双重检查的懒汉式加载
懒汉式单例
1.线程安全
2.采用双重检查
1.volatile保证可见性和有序性
2.当instance被一个线程实例化后,实时地刷新到主内存中的共享变量存储中
3.当一个线程修改了volatile修饰的instance变量,其他线程会立即看到最新的值
将锁进行细化,保证线程安全的前提下,可以多个线程进行实例化获取
我们以为的new操作应该是:
1.分配一块内存 M
2.在内存M 上初始化 DoubleCheck 对象
3.然后M的地址赋值给instance对象
其实new操作通过指令重排后发生:
1.分配一块内存 M
2.然后M的地址赋值给instance对象
3.最后在内存M 上初始化 DoubleCheck 对象
package code01;
public class DoubleCheck {
private static volatile DoubleCheck instance;
private DoubleCheck(){
}
public static DoubleCheck getInstance(){
if(instance==null){
synchronized(DoubleCheck.class){
if(instance==null){
instance= new DoubleCheck();
}
}
}
return instance;
}
}
方式三:静态内部类的懒汉式加载
懒汉式单例
1.线程安全
2.静态内部类实现
外部类StaticInnerSingleton加载时,不会加载静态内部类Inner
只有静态内部类的静态属性被调用时,才会加载,可实现延时加载功能
优点:1.加载机制避免了线程安全问题
JVM必须确保一个类在初始化的过程中,如果是多线程需要同时初始化它,仅仅只能允许其中一个线程对其执行初始化操作,其余线程必须等待。
静态只加载一次
2.方法没有同步,调用效率高
3.保证了懒加载
class StaticInnerSingleton{
private StaticInnerSingleton() {
}
private static class Inner{
private static final StaticInnerSingleton instance =
new StaticInnerSingleton();
}
public static StaticInnerSingleton getInstance() {
return Inner.instance;
}
}
方式四:静态变量或静态代码块的饿汉式加载
优点:采用静态变量或静态代码块,类加载时就完成了instance的实例化,类只加载一次避免线程同步
缺点:如果从始至终都没有使用过这个instance,造成内存的浪费
package code01;
public class Singleton {
//静态变量
private final static Singleton instance1 = new Singleton();
//静态代码块
private final static Singleton instance2;
static{
instance2 = new Singleton();
}
private Singleton(){
}
public static Singleton getInstance1(){
return instance1;
}
public static Singleton getInstance2(){
return instance2;
}
}
方式五:枚举式饿汉式加载
通过类加载机制保证线程安全的
直接通过EasySingleton.INSTANCE进行访问
public enum EasySingleton{
INSTANCE;
}