完美的单例模式建立

  今天把设计模式拿出来看了下,发现之前对于单例模式的理解非常肤浅,没考虑线程安全,在考虑了线程安全的状况下又没考虑性能,固然我遇到的系统都不怎么考虑并发性能,因此其实也无所谓,当看到单例模式的时候,上网搜索了下,发下一片很好的帖子,我把其中的单例模式整理了下,给了个结果出来。html

  帖子地址:http://blog.csdn.net/zhangerqing/article/details/8194653java

  前提都是在考虑线程安全的状况下,能够有两种状况。分别是懒汉式和饿汉式的一种实现。sql

  1.性能不太好,每次锁对象,固然若是你遇到的跟我遇到的系统都同样不考虑性能问题,其实这么作也没问题,可是很差。正如Oracle高级编程里面所说的那样,你的sql能正确的完成任务,但并不表明他能很好的完成任务。编程

  2.咱们只但愿在第一次getInstance的时候去实例化对象,这个就作到了,而且线程安全,可是若是类加载的时候出问题仍是有可能出问题,因此借用那篇帖子里说的,要完成完美的实现是不可能的,咱们只能根据实际状况来选择合适的方式。设计模式

  1.直接锁整个对象,保证线程安全,可是因为每次获取都会锁对象,性能很差,也不是咱们但愿的。安全

package singlePattern;

/**
 * Thread safe single pattern, but performance is poor, because every time we will lock the instance,
 * we hope lock the instance on first time but all times
 * 
 * @author Administrator
 * 
 */
public class SinglePattern {

    // private instance
    private static SinglePattern instance = null;

    // private constructor
    private SinglePattern() {
    }

    // public getInstance method
    public synchronized static SinglePattern getInstance() {
        if (instance == null) {
            instance = new SinglePattern();
        }
        return instance;
    }
}

  2.咱们须要的情形是在第一次初始化须要同步,以后的调用就不须要考虑线程同步。因为JVM在加载类的时候是互斥的,咱们知道类加载器在加载类的时候会直接把静态变量和静态代码块执行一次,而后再去去调用普通代码快,而后去调用构造方法初始化堆,而后在返回引用赋值给栈里面的引用。因而咱们能够利用类加载的静态变量和静态代码块来安全的构造单例实例。并发

  

package singlePattern;

/**
 * Thread safe and performance good.
 * @author Administrator
 *
 */
public class UserSinglePattern {
    
    // private constructor
    private UserSinglePattern() {}
    
    // static inner class, for create a single pattern instance
    private static class NewInstance {
        private static UserSinglePattern instance = new UserSinglePattern();
    }
    
    // the get method for single pattern instance
    public static UserSinglePattern getInstance() {
        return NewInstance.instance;
    }
}

  3.若是实例采用静态的就能实如今类加载的时候线程安全的初始化实例,可是却不能实现lazy加载,而采用上面的静态内部类的方式就能实现lazy加载,由于虚拟机机制是须要调用getInstance()方法的时候才会加载静态内部类,若是不调用那么他是不会被加载的。下面是测试代码,同时拥有2个静态内部类来建立对象,可是只调用其中一个那么就只会加载一个,另一个是不会被加载的。ide

public class SinglePatternThreadSafe {
    
    // 私有构造方法
    private SinglePatternThreadSafe() {
        System.out.println(123);
    }
    
    private SinglePatternThreadSafe(String str) {
        System.out.println(321);
    }
    
    // 内部类,利用类加载的互斥性来达到单例的建立
    private static class NewInstance {
        private static SinglePatternThreadSafe instance = new SinglePatternThreadSafe();
    }
    
    private static class NewInstance1 {
        private static SinglePatternThreadSafe in = new SinglePatternThreadSafe("11");
    }
    
    // 返回实例的公共方法
    public static SinglePatternThreadSafe getInstance() {
        return NewInstance.instance;
    }
    
    public static SinglePatternThreadSafe getInstance(String str) {
        return NewInstance1.in;
    }
    
    public static void main(String[] args) {
        SinglePatternThreadSafe.getInstance();
    }
  // 只打印出123而没有打印11 }

再贴下我参考的地址对做者表示感谢:http://blog.csdn.net/zhangerqing/article/details/8194653性能

这个也写的很好:http://www.cnblogs.com/coffee/archive/2011/12/05/inside-java-singleton.html测试

这篇也测试了若是在不调用静态内部类的方法或者变量或者常量的时候内部类是不会被加载的,http://yongliang567.iteye.com/blog/904467

相关文章
相关标签/搜索