设计模式之单例模式

一、概念

1.单例模式是Java设计模式中最简单的设计模式之一。

2.单例模式属于对象创建型模式

3.单例模式的作用是保证一个类仅有一个实力,并提供一个访问他的全局访问点。

  理解:某些类创建对象是非常消耗内存消耗时间的,这种类创建的对象我们称它为重量级对象,由于重量级对象的这些特征,所以我们如果要使用重量级对象,那么我们就需要把这个类设计为单例模式,这样做的好处有三点:

                              3.1保证对象在内存中只有一个,从而减少内存的开销

                              3.2使用者不需要考虑创建的细节,使用方便

                              3.3可以控制对象的创建时刻

知识点:因为类在整个jvm中仅有一个对象实例:我们需要知道如下两个关键点;

                              对象的创建方式有四种(单例模式要做的就是怎么屏蔽外界能够通过下面的方式创建)

                               .new            .反射         .反序列化         .克隆

                              需要提供一个全局的访问点两种方式

                               .公开的静态变量(不利于扩展)                      .一个公开的静态方法,返回唯一的实例

二、java代码实现 

先看一下我们最原始的写法:

package singletonclass;

public class SingletoClass {
		public void test(){
		System.out.println("哈哈");
	}
}


package singletonclass;

public class Main {
	public static void main(String args[]) {
		
		SingletoClass single1 = new SingletoClass(); //这里我们想创建几个就是几个,所以这里不是单例模式
		single.test();
	}
}

 

         1.饿汉式

   因为是静态static修饰的实例,所以当类加载的时候,实例就进行了加载。

                    1.1针对上面的代码,我们可能最先想到的是,我们将我们类里面的构造方法进行私有化,这样的话,在Main类里面就不能进行实例化了,但是这样Main类中就不能使用了,所以我们需要在SingletoClass类里面提供一个唯一的实例,我们在类里面使用一个公开的静态变量来进行提供访问:

package singletonclass;

public class SingletoClass {
	
	public static final SingletoClass  ONLY = new SingletoClass(); //全局静态变量
	
	private SingletoClass(){
		
	}
	public void test(){
		System.out.println("哈哈");
	}
}


package singletonclass;

public class Main {
	public static void main(String args[]) {
		
		SingletoClass single = SingletoClass.ONLY;
		single.test();
	}
}

                    1.2上面的代码确实实现了单例模式,但是前面我们提到了,这种方式的扩展性不好,假如我们要对那个对象进行一些控制的话,我们是不能编写代码的。所以我们采用公开的静态方法来实现:

package singletonclass;

public class SingletoClass {
	public static final SingletoClass  ONLY = new SingletoClass(); //全局静态变量
	
	private SingletoClass(){
		
	}
    //提供一个全局的访问点
	public static SingletoClass getInstance(){
		return ONLY;
	}
	
	public void test(){
		System.out.println("哈哈");
	}
}


package singletonclass;

public class Main {
	public static void main(String args[]) {
		
		SingletoClass single1 = SingletoClass.getInstance();
		SingletoClass single2 = SingletoClass.getInstance();
		System.out.println(single1==single2);   //这里输出是true,说明只创建了一个对象
		single1.test();
	}
}

 

 

 

         2.懒汉式

上面的饿汉式存在一定的问题,由于是类加载的时候就对其进行了实例化,这样第一是我们不能控制实例创建的时间,第二是,万一我们没用到这个实例,创建无疑是就浪费了。  

package singletonclass;

public class SingletoClass {
	public static SingletoClass  ONLY ; //保存唯一的实例
	
	private SingletoClass(){
		
	}
    //提供一个全局的访问点
	public static SingletoClass getInstance(){
		if(ONLY==null){
			ONLY  = new SingletoClass();
		}
		return ONLY;
	}
	
	public void test(){
		System.out.println("哈哈");
	}
}


package singletonclass;

public class Main {
	public static void main(String args[]) {
		
		SingletoClass single1 = SingletoClass.getInstance();
		SingletoClass single2 = SingletoClass.getInstance();
		System.out.println(single1==single2);
		single1.test();
	}
}


         3.加锁懒汉式

上面的懒汉式严格意义上来说,并不是真正的懒汉式,因为它不是线程安全的,

//在多线程的情况下,线程1发现ONLY==null,进入到了if语句里,就在x线程1还没来得及执行ONLY==new 这句代码的这一瞬间,线程2也发现了ONLY==null也进入到了if语句,这个时候创建就会发生冲突
                       if(ONLY==null){
			  ONLY  = new SingletoClass();
		        }

所以我们需要对其进行同步

 //提供一个全局的访问点
	public static synchronized SingletoClass getInstance(){
		if(ONLY==null){
			ONLY  = new SingletoClass();
		}
		return ONLY;
	}synchronized SingletoClass getInstance(){
		if(ONLY==null){
			ONLY  = new SingletoClass();
		}
		return ONLY;
	}

 

         4.双重验证式懒汉式

上面的加锁懒汉式看上去似乎很完美,但是不然,因为我们采用了同步,效率降低是一方面,第二方面,假如我们ONLY已经实例化了,以后的每次访问还是要执行同步的这样一个操作。这样明显降低效率了。

我们将同步方法改为同步代码块:

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

          5.类加载方式

上面的双重验证确实很完美了,延迟加载,线程安全,效率高,但是还是有个问题,那就是代码的复杂度变高了。

使用内部类的方式来实现:延迟加载,线程安全,效率高,代码简单

package singletonclass;

public class SingletoClass {
	
	//屏蔽外部的new
	private SingletoClass(){
		
	}
	//静态内部类,用于持有唯一的SingletoClass的实例
	private static class OnlyInstanceHoder{
		static private SingletoClass ONLY = new SingletoClass();
	}
  
	//公开一个唯一的访问点
	public static SingletoClass getInstance(){
		return OnlyInstanceHoder.ONLY;
	}
}

 

          6.枚举实现

jdk1.5引入的,具备上面的所有优点。还防止序列化。

package singletonclass;

public enum SingletoClass {

	INSTANCE;

	public void test(){
		System.out.println("single");
	}
}


package singletonclass;

public class Main {
	public static void main(String args[]) {
		
		
		singletonclass.SingletoClass.INSTANCE.test();;
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值