Java常用GoF设计模式之一单例模式

单例模式概念及特点
  java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例、饿汉式单例、登记式单例(应用比较少,不做介绍)三种。
  单例模式有一下特点:
  1、单例类只能有一个实例。
  2、单例类必须自己自己创建自己的唯一实例。

  3、单例类必须给所有其他对象提供这一实例。

单例的使用场景

懒汉式单例模式一(方法加锁):

package cn.gof.singleton;
/**
 * @author zhaopan
 * @date 2016年10月21日 上午10:11:01
 * 单例模式--懒汉式
 * 优点:实现了简单的懒加载,真正用的时候才加载。
 * 缺点:方法同步,调用效率稍低
 */
public class Singleton03 {

	private static Singleton03 singleton03;
	private Singleton03(){
		
	}
	public static synchronized Singleton03 getInstance(){
		if (singleton03==null){
			singleton03=new Singleton03();
		}
		return singleton03;
	}
}

懒汉式单例模式二(双重检测锁机制):

package cn.gof.singleton;
/**
 * @author zhaopan
 * @date 2016年10月21日 上午10:27:50
 * 双重检测锁机制的懒汉式
 * 优点:将同步内容下放到if内部,提高了执行效率,不必每次获取对象时进行同步。
 * 缺点:由于编译器优化和JVM底层内部模型原因,偶尔会出问题,不建议使用。JDK5.0以后版本若instance为volatile则可行
 * 
 * 因为这里的同步只需在第一次创建实例时才同步,一旦创建成功,以后获取实例时就不需要同获取锁了)
 * 但在Java中行不通,因为同步块外面的if (instance == null)可能看到已存在,但不完整的实例。
 * JDK5.0以后版本若instance为volatile则可行
 */
public class Singleton04 {

	//private static Singleton04 singleton04;
	private volatile static Singleton04 singleton04;
	private Singleton04(){
		
	}
	public static Singleton04 getInstance(){
		if(singleton04==null){
			synchronized (Singleton04.class) {
				if(singleton04==null){
					singleton04=new Singleton04();
				}
			}
		}
		return singleton04;
	}
}

为什么用volatile可以保证线程安全参考:

单例模式与双重检测

用happen-before规则重新审视DCL

懒汉式单例模式三(静态内部类的方式):

package cn.gof.singleton;
/**
 * @author zhaopan
 * @date 2016年10月21日 上午10:46:40
 * 静态内部类方式  实现懒汉式单例
 * 优点:并发高效调用和延时加载的优势。
 * 外部类没有static属性,则不会像俄汉式那样立即加载对象。
 * 只有真正调用getInstance(),才会加载静态内部类。加载类时是线程安全的。
 * 因为instance是static final 类型,保证了内存中只有这样一个实例存在,而且只能被赋值一次,从而保证线程安全性。
 * 
 */
public class Singleton05 {

	private Singleton05(){
		
	}
	public static class SingletonInstance{
		private static final Singleton05 SINGLETON05 =new Singleton05();
	}
	
	public static Singleton05 getInstance(){
		return SingletonInstance.SINGLETON05;
	}
	
}

饿汉式单例模式一(静态常量实现):

package cn.gof.singleton;
/**
 * @author zhaopan
 * @date 2016年10月21日 上午10:03:35
 * 最简单的单例模式 饿汉式
 * 		
 * 优点:static,此时不会设计多个线程对象访问该对象的问题。变量会在类加载时初始化线程安全,调用效率高
 * 缺点:无法实现延迟加载,如果是加载本类,而没有使用,则会造成资源浪费。
 */
public class Singleton01 {
	
	private static final Singleton01 singleton01=new Singleton01();
	//私有化构造方法
	private Singleton01() {
		
	}
	//提供公有的获取实例的方法
	public static Singleton01 getInstance(){
		return singleton01;
	}
	
	
	
}

饿汉式单例模式二(枚举实现):

package cn.gof.singleton;
/**
 * @author zhaopan
 * @date 2016年10月21日 上午10:37:48
 * 枚举实现饿汉式单例模式
 * 优点:1、 自由序列化;2、 保证只有一个实例(即使使用反射机制也无法多次实例化一个枚举量);3、 线程安全;
 * 缺点:无延时加载
 */
public enum Singleton02 {

	INSTANCE;
	public void sayHi(){
		System.out.println("我是枚举类型的单例");
	}
	
}

测试效率:

package cn.gof.singleton;
/**
 * @author zhaopan
 * @date 2016年10月21日 下午4:57:02
 * 
 */
import java.util.concurrent.CountDownLatch;  
  
/** 
 * 测试多线程环境下五种创建单例模式的效率 
 * @author liguodong 
 * 
 */  
public class ClientTest {  
    public static void main(String[] args) throws InterruptedException {  
          
        long start = System.nanoTime();  
        int threadNum = 10; 
        long sum=0;
        final CountDownLatch count = new CountDownLatch(threadNum);  
        int[] ins=new int[10];
        for(int j=0;j<100;j++) {        
	        for(int i=0;i<10;i++) {  
	            new Thread(new Runnable() {  
	                  
	                @Override  
	                public void run() {  
	                    // TODO Auto-generated method stub  
	                    for(int i=0;i<1000000;i++)  
	                    {  
	                    	/**
	                    	 * 饿汉式
	                    	 */
	                       // Object o = Singleton01.getInstance(); //普通饿汉式118755558---143202450
	                       //Object o = Singleton02.INSTANCE;//枚举式的111872193---163903002  大部分是11-13
	                    	/**
	                    	 * 懒汉式
	                    	 */
	                    	//Singleton03 instance = Singleton03.getInstance(); //方法加同步关键字2126685034
	                    	//Singleton04 instance2 = Singleton04.getInstance();//将方法内部加同步464849105
	                        //Object o = Singleton05.getInstance();  //内部类的方式  118638630--134209601
	                    }  
	                    count.countDown();  
	                      
	                }  
	            }).start();  
	        }  
        
	        count.await();//main线程阻塞,直到计数器变为0,才会继续往下执行。  
	        long end = System.nanoTime(); 
	        
	        sum=sum+end-start;
        }
        System.out.println("总耗时:"+(sum/100));  
    }  
}  
比较两种模式?
单例对象  占用资源少,不需要延时加载:
枚举式好与 饿汉式
单例对象  占用资源大,需要延时加载:
静态内部类式好于懒汉式

你可能感兴趣的:(Java常用GoF设计模式之一单例模式)