设计模式学习05----之单例模式

单例模式,是我们最常用也最熟悉的一种设计模式,其使用要注意线程安全。
定义

单例模式:顾名思义,就是在应用中有且只有一个实例。一般类似于计数器类的都必须是单例,多例会导致计数结果不准。
一般而言,其分为饿汉式和懒汉式。
懒汉式

懒汉式:顾名思义,就是不在系统加载时创建类的实例。而是在调用时才去一次性创建。
demo如下:

package com.singleton;

/**
 * 懒汉式
 * @author xiang.wei
 */
public class LazySingleton {
    /**
     * 定义一个私有变量,目的是外部不能直接访问该变量,必须通过公共的访问方法来访问
     */
    private static LazySingleton instance=null;

    /**
     * 私有化构造器,使之不能直接构造对象
     */
    private LazySingleton(){
       
    }

    /**
     * 公共的提取对象的方法
     * @return
     */
    public synchronized static LazySingleton getInstance() {
        if (instance==null) {
             instance=new LazySingleton();
        }
        return instance;
    }
}



饿汉式

饿汉式:与懒汉式相反,饿汉式就是在系统加载时就去创建类的实例。
demo如下:

package com.singleton;

/**
 * 饿汉式
 * @author xiang.wei
 * @create 2018/4/10 10:34
 */
public class HungrySingleton {
    private static final HungrySingleton SINGLETON = new HungrySingleton();

    private HungrySingleton() {
    }

    public static HungrySingleton getInstance() {
        return SINGLETON;
    }
}



总结:饿汉式与懒汉式相比要占用更多的内存,因为系统加载之后就会创建实例。但是效率要比懒汉式要高。
双重加锁

双重加锁是懒汉式的一种扩展。因为直接在getInstance()上加上synchronized会导致每次调用方法时都需要加锁。执行效率不高。所以,我们采用了双重加锁的方式。

package com.singleton;

/**
 * 懒汉式
 * 双重加锁
 * @author xiang.wei
 */
public class LazySingleton_two {
    /**
     * 定义一个私有变量,目的是外部不能直接访问该变量,必须通过公共的访问方法来访问
     */
    private static  volatile LazySingleton_two instance = null;

    /**
     * 私有化构造器,使之不能直接构造对象
     */
    private LazySingleton_two() {

    }

    /**
     * 公共的提取对象的方法
     *
     * @return
     */
    public static LazySingleton_two getInstance() {
        //如果单例存在则直接返回
        if (instance == null) {
            //单例不存在,则进入同步代码块
            synchronized (LazySingleton_two.class) {
                if (instance == null) {
                    System.out.println("实例化的次数");
                    instance = new LazySingleton_two();
                }
            }
        }
        return instance;
    }
}

 

双重加锁并不是加两个synchronized关键字。
第一个判断是当对象存在时则直接返回实例,当对象不存在时则进入同步代码块中,同步代码块的作用跟之前是相同的,就是防止两个线程同时访问同步代码块的内容,造成生成多个实例的情况。同步代码块每次只允许一个线程进入,创建完实例后返回。第二个判断是当多个线程排队进入代码块时,第一个线程创建完实例返回后,第二个线程再进入时,不需要在创建实例。
采用双重加锁后,代码的执行效率有了较大的提升。
静态内部类的方式

public class MySingleton {

    private static class MySingletonHandle {
        private static final MySingleton instance = new MySingleton();
    }

    private MySingleton() {

    }

    public MySingleton getSingleton() {
        return MySingletonHandle.instance;
    }
}





作者:码农飞哥
微信公众号:码农飞哥