单例-饿汉式

 

   /**  
     * @Title: Singleton.java
     * @Package org.chisj.single
     * @Description: TODO
     * @author chisj chisj@foxmail.com
     * @date 2017年3月24日
     */
    package org.chisj.single;
    
    // 单例模式确保某个类只有一个实例, 而且自行实例化并向整个系统提供这个实例。
    // 线程池、日志对象、对话框、打印机、先看的驱动程序对象进程被设计成单例。
    // 选择单例模式是为了避免不一致的状态,避免政出多头
    
    /**
     * ClassName: Singleton 
     * @Description: 懒汉式单例,在第一次调用的时候实例自己
     * @author chisj chisj@foxmail.com
     * @date 2017年3月24日
     */
    public class Singleton {
    
    	// Singleton通过将构造方法限定为private, 避免了类在外部被实例化, 
    	// 在同一个虚拟机范围内, Singleton的唯一实例化只能通过getInstance()方法访问
    	// 事实上, 通过Java反射机制是能够实现实例化构造方法为private类
    	// 基本上会使得所有的Java单例实现失效, 所以我们默认认为反射机制不存在
    	private Singleton() {}
    	
    	private static Singleton single = null;
    	
    	// 静态工厂方法
    	// 没有考虑线程安全问题, 所以是线程不安全的, 并发环境下很可能出现多个Singleton的实例
    	/*
    	public static Singleton getInstance() {
    		// 判断实例是否被创建初始化
    		if (single == null) {
    			// 没有创建实例对象的时候进行创建
    			single = new Singleton();
    		}
    		return null;
    	}
    	*/
    	
    	// 加上synchronized同步
    	/*
    	public static synchronized Singleton getInstance() {
    		if (single == null) {
    			single = new Singleton();
    		}
    		return single;
    	}
    	*/
    	
    	// 双重检查锁定
    	/*
    	public static Singleton getInstance() {
    		if (single == null) {
    			synchronized (Singleton.class) {
    				if (single == null) {
    					single = new Singleton();
    				}
    			}
    		}
    		return single;
    	}
    	*/
    	
    	// 静态内部类
    	// 这种方法比上面的1, 2都好一些, 既实现线程安全, 又避免了同步带来的性能问题
    	private static class LazyHolder {
    		private static final Singleton INSTANCE = new Singleton();
    	}
    	
    	public static final Singleton geInstance() {
    		return LazyHolder.INSTANCE;
    	}
    	
    }
    
    // 单例模式的实现方式有三种:懒汉式单例, 饿汉式单例, 登记式单例
    // 单例模式的特点:
    // 1.单例类只能有一个实例.
    // 2.单例类必须自己创建自己的唯一实例.
    // 3.单例类必须给所有其他对象提供这一实例.

 


单例-懒汉式

 

 

    /**  
     * @Title: Singleton1.java
     * @Package org.chisj.single
     * @Description: TODO
     * @author chisj chisj@foxmail.com
     * @date 2017年3月24日
     */
    package org.chisj.single;
    
    /**
     * ClassName: Singleton1 
     * @Description: 恶汉式单例类,在类初始化时已经自行实例化
     * @author chisj chisj@foxmail.com
     * @date 2017年3月24日
     */
    public class Singleton1 {
    
    	private Singleton1() {}
    	
    	private static final Singleton1 single = new Singleton1();
    	
    	// 静态工厂方法
    	public static Singleton1 getInstance() {
    		return single;
    	}
    	
    }
    // 说明
    // 饿汉式在类床架的同时已经创建好一个静态的对象供系统使用, 以后不再改变, 所以天生是线程安全的
    
    // 饿汉式和懒汉式区别
    // 饿汉式的类一旦加载, 就把单例初始化完成, 保存getInstance的时候, 单例是已经存在的了
    // 懒汉式比较懒, 只有当抵用getInstance的时候, 才回去初始这个单例
    
    // 1.线程安全
    // 饿汉式天生就是线程安全的, 可以直接用于多线程而不会出现问题.
    // 懒汉式本身是非线程安全的, 为了实现线程安全有几种写法, 分别是上面的1、2、3, 这三种实现在资源加载和性能方面有些区别
    
    // 2.资源加载和性能
    // 饿汉式在类创建的同时就实例化一个静态对象出来, 不管之后会不会使用这个单例, 都会占据一定的内存, 
    // 但是相应的, 在第一次调用时速度也会更快, 因为其资源已经初始化完成。
    
    // 单例模式为一个面向对象的应用程序提供了对象唯一的访问点, 不管她实现何种功能, 整个应用程序都会同享一个实例对象

 


单例--登记式

 

 

  /**  
     * @Title: Singleton2.java
     * @Package org.chisj.single
     * @Description: TODO
     * @author chisj chisj@foxmail.com
     * @date 2017年3月24日
     */
    package org.chisj.single;
    
    import java.util.HashMap;
    import java.util.Map;
    
    // 登记式单例维护了一组单例类的实例, 将这些实例存放在一个Map(登记薄)中, 
    // 对于已经登记过的实例, 则从Map直接返回, 对于没有登记的, 则先登记, 然后返回.
    
    /**
     * ClassName: Singleton2 
     * @Description: 登记式单例, 类似于Spring里面的方法, 将类名注册, 下次从里面直接获取
     * @author chisj chisj@foxmail.com
     * @date 2017年3月24日
     */
    public class Singleton2 {
    
    	private static Map<String, Singleton2> map = new HashMap<String, Singleton2>();
    	
    	static {
    		Singleton2 single = new Singleton2();
    		map.put(single.getClass().getName(), single);
    	}
    	
    	// 保护的默认构造
    	protected Singleton2() {};
    	
    	public static Singleton2 getInstance(String name) {
    		if (name == null) {
    			name = Singleton2.class.getName();
    			System.out.println("name == null " + " ---> name = " + name);
    		}
    		if (map.get(name) == null) {
    			try {
    				map.put(name, (Singleton2) Class.forName(name).newInstance());
    			} catch (InstantiationException e) {
    				e.printStackTrace();
    			} catch (IllegalAccessException e) {
    				// TODO: handle exception
    				e.printStackTrace();
    			} catch (ClassNotFoundException e) {
    				// TODO: handle exception
    				e.printStackTrace();
    			}
    		}
    		return map.get(name);
    	}
    	
    	// 一个示意性的商业方法
    	public String about() {
    		return "Hello, I am RegSingleton.";
    	}
    	
    	public static void main(String[] args) {
    		Singleton2 single2 = Singleton2.getInstance(null);
    		System.out.println(single2.about());
    	}
    }