【GOF23设计模式】_单例模式


1):饿汉式(线程安全,调用效率高,但是不能延时加载)

/**
 * 饿汉式单例模式
 * 
 * @author Cc
 * 
 */
public class Singleton {


private static Singleton instance = new Singleton();   // 类初始化时,立即加载这个对象(无延时加载的优势).天然是线程安全的。


// 私有构造器
private Singleton() {
}


// 方法没有同步,调用效率高
private static Singleton getInstence() {
return instance;
}

}


另一种写法:

public class Singleton_1_1 {
private static Singleton_1_1 instance = null;
static {
instance = new Singleton_1_1();
}


private Singleton_1_1() {
}


public static Singleton_1_1 getInstance() {
return instance;
}
}


和上面的没啥区别,都是在类初始化时实例化类



2):懒汉式( 线程安全,调用效率高,可以延时加载)


/**
 * 懒汉式
 * 
 * 要点:真正用的时候才加载。
 * 缺点:虽然资源利用效率高了,但每次调用getInstence()方法都要同步,并发效率低。
 * 
 * @author Cc
 * 
 */
public class Singleton_1 {
private static Singleton_1 instance;


// 1.私有构造器
private Singleton_1() {
}


//方法同步,调用效率低
private static synchronizedSingleton_1 getInstence() { //synchronized 加上这个就线程安全,但是效率很低,不加的话,多线程不能正常工作
if (instance == null) {
instance = new Singleton_1();
}
return instance;
}
}




3):双重检测锁式(由于JVM底层内部模型原因,偶尔会出现问题)


/**
 * 双从检测锁
 * @author Cc
 *
 */


public class Singleton_2 {
private volatile static Singleton_2 singleton;


private Singleton_2() {
}


public static Singleton_2 getSingleton() {
if (singleton == null) {
synchronized (Singleton_2.class) {
if (singleton == null) {
singleton = new Singleton_2();
}
}
}
return singleton;
}
}

注:在JDK1.5之后,双重检查锁定才能够正常达到单例效果。


4):静态内部类式(线程安全,调用效率高,可延时加载)



/**
 * 静态内部类
 * 这种方式同样利用了classloder的机制来保证初始化instance时只有一个线程,
 * 它跟恶汉方式不同的是(很细微的差别):恶汉方式是只要Singleton类被装载了,
 * 那么instance就会被实例化(没有达到lazy loading效果),而这种方式是Singleton类被装载了,
 * instance不一定被初始化。因为SingletonInstence类没有被主动使用,
 * 只有显示通过调用getInstance方法时,才会显示装载SingletonInstence类,从而实例化instance。想象一下,
 * 如果实例化instance很消耗资源,我想让他延迟加载,另外一方面,我不希望在Singleton类加载时就实例化,
 * 因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化instance显然
 * 是不合适的。
 * @author Cc
 *
 */


public class Singleton_3 {
private static class SingletonInstence {
private static final Singleton_3 instence = new Singleton_3();
}


public static Singleton_3 getInstence() {
return SingletonInstence.instence;
}


private Singleton_3() {
}


}


5):枚举单例(线程安全,调用效率高,不能延时加载)



public enum Singleton_4 {

/**
* 优点:实现简单,枚举本身就是单例模式。由JVM从根本上提供保障。避免反射和反序列化的漏洞。
* 缺点:无延迟加载,无懒加载效果。
*/


INSTENCE;


/**
* 通过Singleton_4.INSTENCE就可以调用
*/
// 添加自己需要的操作
public void SingletonOperation() {


}


}




.

总结

有两个问题需要注意:
1.如果单例由不同的类装载器装入,那便有可能存在多个单例类的实例。假定不是远端存取,例如一些servlet容器对每个servlet使用完全不同的类装载器,这样的话如果有两个servlet访问一个单例类,它们就都会有各自的实例。
2.如果Singleton实现了java.io.Serializable接口,那么这个类的实例就可能被序列化和复原。不管怎样,如果你序列化一个单例类的对象,接下来复原多个那个对象,那你就会有多个单例类的实例。
对第一个问题修复的办法是:

private static Class getClass(String classname)      
    throws ClassNotFoundException {     
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();     


if(classLoader == null)     
classLoader = Singleton.class.getClassLoader();     


return (classLoader.loadClass(classname));     
}     


 对第二个问题修复的办法是:



public class Singleton implements java.io.Serializable {     
  public static Singleton INSTANCE = new Singleton();     
     
  protected Singleton() {     
       
  }     
  private Object readResolve() {     
           return INSTANCE;     
     }    
}    


整理自:


        尚学堂 (http://www.bjsxt.com/)视频


        http://cantellow.iteye.com/blog/838473


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值