Java设计模式中的单例设计模式

单例模式(Singleton pattern)

Java单例设计模式中,要求JVM中只有这个类的一个实例,在此简单总结一下Java的几个实现该模式的方法。

  • 方法一:饿汉式单例,有如下几个要点
  1. 构造方法私有化,不允许其他类创建本类的实例
  2. 由本类自己创建本类的一个实例
  3. 创建一个方法,通过方法来获取本类的实例

观察例子:


/*
 * @author F3ver1
 * @date 2018/11/26 22:29
 */
class Singleton {
	//1.构造方法私有化
    private Singleton(){ 

    }
	//2.在本类中创建实例
    private static final Singleton SINGLETON = new Singleton();
    
	//3.创建方法获得本类实例
    public static Singleton getSingleton(){
        return SINGLETON;
    }

}
public class Singleton1{
    public static void main(String[] args) {
        Singleton singleton = Singleton.getSingleton();
        Singleton singleton1 = Singleton.getSingleton();
        System.out.println(singleton==singleton1);
    }
}

得到结果为true,即该类只能得到一个实例

  • 方法二:懒汉式单例,要点如下(仅仅适用于单线程环境下,稍后再说)
  1. 构造方法私有化
  2. 在本类中声明本类实例
  3. 利用方法来创建对象

代码如下:

/*
 * @author F3ver1
 * @date 2018/11/26 22:39
 */
class Singleton{
	//1.构造方法私有化
    private Singleton(){
        
    }
    //2.声明本类对象
    private static Singleton SINGLETON;
    //3.通过方法创建本类对象
    public static Singleton getSINGLETON(){
        if(SINGLETON == null) {
            SINGLETON = new Singleton();
        }
        return SINGLETON;
    }
    
}
public class Singleton2 {
    public static void main(String[] args) {
        Singleton singleton = Singleton.getSINGLETON();
        Singleton singleton1 = Singleton.getSINGLETON();
        System.out.println(singleton==singleton1);
    }
}

以上代码在单线程环境下毫无问题,但是如果在多线程下就不再能完成任务,也就是多线程以上代码是可能出现多个实例的,当线程1判断if(SINGLETON==null)时,线程2同时也判断该语句,则两个线程都认为此时SINGLETON的值都为NULL,而未实例化,因此就不再是单例了,在这里只需要在静态方法getSINGLETON加上关键字Synchronized即可。

  • 方法三:懒汉式优化
    在方法二中,我们认为在方法上加上Synchronized关键字有损效率,因为在多线程下,这个方法只需要锁住第一次即可,也就是说,只要保证第一次创建对象时,其他线程无法干扰就可以了,但是在方法上加上Synchronized关键字,每个线程执行该方法都会上一次锁,这样效率影响不小,因此这里给出更好的版本

/*
* @author F3ver1
* @date 2018/11/28 19:23
*/
class Singleton{
   //1.构造方法私有化
   private Singleton(){

   }
   static {
       System.out.println("Singleton类被加载");
   }
   //2.创建私有静态内部类,通过类来创建对象且保证单例性
   private static class Single{
       static {
           System.out.println("Single类被加载");
       }
       static Singleton SINGLETON = new Singleton();

   }//3.通过本类方法加载内部类
   public static Singleton getSINGLETON(){
       return Single.SINGLETON;
   }
   public static void test(){
       System.out.println("Singleton类其他方法被加载");
   }
}

public class Singleton3 {

   public static void main(String[] args) { 
       Singleton.test();
   }
}

结果打印:
Singleton类被加载
Singleton类其他方法被加载

结果得知当调用Singleton其他方法时并不会加载其内部类而创建对象,仅仅只有当调用Singleton中的getSINGLETON方法才能得到其对象

public class Singleton3 {

    public static void main(String[] args) {
        Singleton singleton = Singleton.getSINGLETON();
        Singleton singleton1 = Singleton.getSINGLETON();
        System.out.println(singleton==singleton1);
    }
}

结果得到true

这里我们依靠getSINGLETON()方法来使Singleton类中的内部类得到加载,因为类的加载一次运行只能存在一次,之后再调用类不会再被重复加载,依靠这个特点,来创建单例对象,并且一定是线程安全的。
  • 方法四:枚举实现
    枚举用于对象数目固定的场景,因此也可以用于单例模式,给出最简单的情况参考
/*
 * @author F3ver1
 * @date 2018/11/28 19:59
 */
enum Singleton{
    SINGLETON;
    Singleton(){

    }
}
public class Singleton4 {
    public static void main(String[] args) {
        Singleton singleton = Singleton.SINGLETON;
        Singleton singleton1 = Singleton.SINGLETON;
        System.out.println(singleton==singleton1);
    }
}

结果同样得到true。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值