单例模式是什么?线程安全?

单例模式介绍

        单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

        单例模式确保一个类最多只有一个实例,并提供一个全局访问点。

优点:
        1.在内存中只有一个对象,节省内存空间;
        2.避免频繁的创建销毁对象,可以提高性能;
        3.避免对共享资源的多重占用,简化访问;
        4.为整个系统提供一个全局访问点。
缺点:
        1.不适用于变化频繁的对象;
        2.存在线程不安全的问题;
        3.如果实例化的对象长时间不被利用,系统会认为该对象是垃圾而被回收,这可能会导致对象状态的丢失;

代码实现

        单例模式可分为,饿汉式,懒汉式,还有一种双锁模式

饿汉式具体实现

        饿汉式,顾名思义就是在单例类被加载时,就会实例化一个对象并交给自己的引用,供系统使用。这种方法是线程安全的,不过要是加载的对象没有被使用就会造成资源的浪费。

public class PreloadSingleton {
       
       
       public static PreloadSingleton instance = new PreloadSingleton();
   
       //私有化构造方法
       private PreloadSingleton() {
       };
       
       public static PreloadSingleton getInstance() {
              return instance;
       }
}

懒汉式具体实现

        为了避免内存的浪费,我们可以采用懒汉式的方法,即用到该单例对象的时候再创建。这样可以有效的避免资源被浪费的问题,不过会带来线程安全问题。

public class Singleton {
       
       private static Singleton instance=null;
       
       private Singleton(){
       };
       
       public static Singleton getInstance()
       {
              if(instance==null)
              {
                     instance=new Singleton();
              }
              return instance;
              
       }
}

        为什么这种方法无法保证线程安全?

        原因就在于不满足原子性或者顺序性。创建一个对象分为3步:初始化内存空间,初始化对象,分配的内存地址。jvm为了提高程序执行性能,会对没有依赖关系的代码进行重排序,上面2和3行代码可能被重新排序。即:可能先分配地址,再初始化对象。

        假设现在有两个线程,都使用这种方式创建对象。线程A先分配了内存地址,但是没有初始化对象。线程B在这时检查到内存地址不为null,线程B接下来将访问instance引用的对象。也就是说线程B将会访问到一个还未初始化的对象。造成空指针异常,线程不安全!

双锁单例模式

        为了解决懒汉式线程不安全的问题,可以引入锁来解决.。在创建对象时加入锁,并且加入关键字volatile保证对象实例化过程的顺序性。

public class Singleton {
    private volatile static Singleton instance;
    private Singleton (){}
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

        使用双锁单例就成功的保证了单例模式的线程安全问题。

总结

        饿汉式保证了线程安全但是可能会造成资源浪费。

        懒汉式资源不会浪费但是会造成线程不安全的问题。

猜你喜欢

转载自blog.csdn.net/m0_58366209/article/details/127843703