您的位置:首页 > 编程语言 > Go语言

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

2016-04-03 01:26 501 查看
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接口,那么这个
c2f8
类的实例就可能被序列化和复原。不管怎样,如果你序列化一个单例类的对象,接下来复原多个那个对象,那你就会有多个单例类的实例。

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

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: