积跬步至千里

JAVA 单例模式总结

1.单列模式
1.手写单例模式 2.线程安全的单例模式

什么是单例模式?

单例类在整个程序中只能有一个实例,这个类负责创建自己的对象,并确保只有一个对象被创建。

在什么情况下使用单例?一般全局使用的类写成单例,会消耗许多系统资源的类写成单例(数据库连接池、工厂类、数据源、sping bean的作用域等)(创建销毁都需要消耗许多系统资源)。

代码实现要点 a) 私有化构造方法 b) 持有该类的属性(创建对象) c) 对外提供获取对象的静态方法

1)饿汉式是典型的单例模式(没有加锁),通过JAVA的类加载机制实现。类加载机制默认是线程安全的,类加载成功,静态属性被初始化,即对象初始化是无延迟的。 饿汉式:线程安全、反射不安全、反序列化不安全(添加readResolve()方法可以保证反序列化安全)

/*
饿汉式
 */
public class Singleton1
{
    private Singleton1()//私有化构造方法
    {}
    private static Singleton1 instance= new Singleton1();//当前类的属性(静态可以全局应用)
​
    public static Singleton1 getInstance()//对外提供获取对象的静态方法
    {
        return instance;
    }
}

2)登记式:线程安全、防止反射攻击、反序列化不安全(添加readResolve()方法可以保证反序列化安全)

延迟初始化

/*
登记式
 */
public class Singleton2
{
    private Singleton2()//私有化构造方法
    {
        if(SingletonHolder.instance != null)
        {
            throw new IllegalStateException();  //若静态内部类方法不为空则抛出状态异常
        }
    }
​
    private static class SingletonHolder{
        private static Singleton2 instance = new Singleton2(); //静态内部类
    }
​
    public static Singleton2 getInstance()
    {
        return SingletonHolder.instance;   //对外提供获取对象的静态方法
    }
​
}

3)枚举式:线程安全、反射安全(没有构造方法)、反序列化安全

/*
枚举式
 */
public enum  Singleton3
{
    INSTANCE //枚举中的对象实现方法
            {
                protected void doSomething()
                {
                    System.out.println("doSomething");
                }
            };
            protected abstract void doSomething();
}

4)懒汉式

/*
懒汉式  同步方法
 */
public class Singleton4
{
    private Singleton4()  //私有化构造方法
    {}
    private static Singleton4 instance = null;  //持有当前类的属性
​
    public static synchronized Singleton4 getInstance()  //对外提供获取对象的静态方法
    {
        if(instance == null)
        {
            instance =new Singleton4();
        }
        return instance;
    }
}
/*
懒汉式   同步代码块
 */
public class Singleton4
{
    private Singleton4()  //私有化构造方法
    {
    }
​
    private static Singleton4 instance = null;  //持有当前类的属性
​
    public static Singleton4 getInstance()  //对外提供获取对象的静态方法
    {
        synchronized (Singleton4.class)
        {
            if (instance == null)
            {
                instance = new Singleton4();
            }
            return instance;
        }
    }
}

5)双重检锁

/*
   双重检锁
 */
public class Singleton5
{
    private Singleton5()  //私有化构造方法
    {
    }
    //双检锁加volatile关键字解决指令重排
    private static volatile Singleton5 instance = null;  //持有当前类的属性
​
    public static Singleton5 getInstance()  //对外提供获取对象的静态方法
    {
        if (instance == null)//双重检锁  效率高
        {
            synchronized (Singleton5.class)
            {
                if (instance == null)
                {
                    instance = new Singleton5();
                }
​
            }
        }
        return instance;
    }
​
}
/*instance=new Singleton5()会执行如下操作:
(1)分配对象内存空间
(2)初始化对象
(3)instance指向(1)中分配的空间
​
在某些编译器上,可能会出现指令重排:
(1)分配对象内存空间
(2)instance指向(1)中分配的空间(但此时对象没有初始化)
(3)初始化对象
​
解决方法:在当前对象前加volatile关键字,确保不出现指令重排
*/

6)ThreadLocal

ThreadLocal:不加锁,以空间换时间,为每个线程提供变量的独立副本

/*
TreadLocal   只能保证一个线程内是单例的(即一个线程同时获取多个对象是同一对象)  不能保证多个线程间是单例的
 */
public class Singleton6
{
    private Singleton6()
    {
    }
​
    private static Singleton6 instance = null;  //延时创建对象
​
    private static final ThreadLocal<Singleton6> thread = new ThreadLocal<Singleton6>()
    {
        @Override
        protected Singleton6 initialValue() //重写初始化方法
        {
            return new Singleton6();
        }
    };
​
    public static Singleton6 getInstance()
    {
        return thread.get();
    }
}

7)CAS( Compare-and-Swap)

无锁的乐观策略:假设进程访问资源不会产生冲突,如果出现冲突就重试当前的操作

/*
CAS  
 */
public class Singleton7
{
    private Singleton7()
    {
    }
​
    //原子类的封装
    private static final AtomicReference<Singleton7> instance = new AtomicReference<Singleton7>();
​
    public static final Singleton7 getInstance()
    {
        for (; ; )//线程重试
        {
            Singleton7 current = instance.get();//拿到原子类引用instance指向的对象current
            if (current != null)
            {
                return current;  //判断current指向对象是否为null,非null返回
            }
            current = new Singleton7(); //为null就创建对象 (延时加载)
            if (instance.compareAndSet(null, current))//调用原子类的compareAndSet方法进行判断
            {                                               
                return current; //如果此时instance指向是null,则用current替换instance
            }
        }
    }
}
posted @ 2021-07-06 21:26  大阿张  阅读(39)  评论(0编辑  收藏  举报