设计模式_单例模式的几种实现方式

  单例模式是一个老生常谈的问题,这里对单例模式的实现做一下总结。

 

分类

  • 懒汉模式
  • 饿汉模式
  • IoDH技术-懒汉模式与饿汉模式的结合

优势与劣势

  • 懒汉模式
  • 饿汉模式
  • IoDH技术-懒汉模式与饿汉模式的结合

 

 

分类

懒汉模式

   懒汉模式是一种直到单例模式需要使用的时候才进行加载的技术。单例模式重要的一个点,是要保证多线程操作的正确性。为此,不同的懒汉模式实现上有了多种确保线程安全的方式。

   synchronized 可以确保方法的线程安全性,具体的做法用使用 sychronized 修饰的方法和 sychronized 修饰的代码块两种方式。

 

synchronized 方法修饰的单例模式

package mode;

/**
 * Created by szh on 2020/6/28.
 *
 * @author szh
 */
public class SingletonOne {

    private static SingletonOne singletonOne = null;

    private SingletonOne() {

    }

    public synchronized static SingletonOne getInstance(){
        if(singletonOne == null){
            singletonOne = new SingletonOne();
        }
        return singletonOne;
    }

    public static void main(String[] args) {
        
        SingletonOne.getInstance();
        System.out.println("------------------------");
    }


}

   上述代码存在一定的问题,每次调用 getInstance() 时都需要进行线程锁定判断,在多线程高并发访问环境中,将会导致系统性能大大降低。

 

synchronized 代码块修饰的单例模式

 针对 synchronized 修饰的方法,可以减低锁的粒度,降低为代码块级别,下面是具体的代码:

package mode;

/**
 * Created by szh on 2020/6/28.
 *
 * @author szh
 */
public class SingletonTwo {

    private static volatile SingletonTwo singletonTwo = null;

    private SingletonTwo() {
        System.out.println("init");
    }

    public static SingletonTwo getInstance() {
        if (singletonTwo == null) {
            synchronized (SingletonTwo.class) {
                if (singletonTwo == null) {
                    singletonTwo = new SingletonTwo();
                }
            }
        }
        return singletonTwo;
    }

    public static void main(String[] args) {
        SingletonTwo.getInstance();
        System.out.println("=======================");
    }
}
  • volatile 修饰静态成员变量

      需要注意一点,需要用 volatile 修饰 静态成员变量,保证不被代码优化导致的双重检查失效。但是也需要注意,volatile 关键字会屏蔽 Java虚拟机锁做的一些代码优化,可能会导致系统运行效率较低。因此,使用双重检查锁来实现单例模式也不是一种完美的实现方式。

 

 

饿汉模式

饿汉模式,可以确保类在被加载时就将自己实例化,可以不需要考虑多线程访问的问题。

下面是具体的代码

package mode;

/**
 * Created by szh on 2020/6/29.
 */
public class SingletonThree {

    private static SingletonThree singletonThree = new SingletonThree();

    private SingletonThree(){
        System.out.println("init");
    }


    public static SingletonThree getInstance(){
        return singletonThree;
    }

    public static void main(String[] args){

        SingletonThree.getInstance();
        System.out.println("-----------------------------");
    }


}

   饿汉模式也存在了一定问题,上面的代码虽然解决了线程安全的问题,但是每次调用 getInstance() 时候都需要进行线程锁定判断,在多线程高并发访问环境中,将会导致系统性能大大降低。

 

 

IoDH技术-懒汉模式与饿汉模式的结合

package mode;

/**
 * Created by szh on 2020/6/29.
 */
public class SingletonFour {

    private SingletonFour(){
        System.out.println("init");
    }

    private static class SingletonFourInner{
        private final static SingletonFour instance = new SingletonFour();
    }

    private static SingletonFour getInstance(){
        return SingletonFourInner.instance;
    }

    public static void main(String[] args){

        SingletonFour.getInstance();
        System.out.println("----------------------------");
    }

}

解析 :

  静态单例对象并没有作为Singleton的成员变量直接实例化,因此类加载时候并不会实例化Sinleton。

  只有第一次调用 getInstance() 时将加载内部类,由Java虚拟机确保线程安全性,确保该成员变量只能初始化一次。

 

 

 

 

优势与劣势

  • 懒汉模式

优势:类只要使用的时候才进行加载

劣势:1)需要复杂的代码确保线程安全性

           2)即使确保线程安全性,效率并非最高

 

  • 饿汉模式

优势:代码简单,不需要考虑多线程安全问题

劣势:在类未被使用的时候就生成实例,性能最差

 

  • IoDH技术-懒汉模式与饿汉模式的结合

优势:性能最高

劣势:具有语言特性,Java外其他语言并不支持

你可能感兴趣的:(设计模式)