zoukankan      html  css  js  c++  java
  • java基础--单例模式的7种实现【转载】

     转载:http://www.blogjava.net/kenzhh/archive/2013/03/15/357824.html

    第一种,线程不安全(懒汉模式)

     1 public class Singleton1 {
     2     private static Singleton1 instance;
     3     private Singleton1(){}
     4     public static Singleton1 getInstance(){
     5         if(instance == null){
     6             instance = new Singleton1();
     7         }
     8         return instance;
     9     }
    10 }

    lazy loading,但是多线程不安全。不推荐。

    第二种,线程安全(懒汉模式)

     1 public class Singleton2 {
     2     private static Singleton2 instance;
     3     private Singleton2(){}
     4     public static synchronized Singleton2 getInstance(){
     5         if(instance == null){
     6             instance = new Singleton2();
     7         }
     8         return instance;
     9     }
    10 }

    lazy loading,线程安全,但是效率极其低下,同步锁锁的是对象,每次取对象都有加锁,因此不推荐,性能很低。

    第三种,线程安全(饿汉模式)

    1 public class Singleton3 {
    2     private static Singleton3 instance = new Singleton3();
    3     private Singleton3(){}
    4     public static synchronized Singleton3 getInstance(){
    5         return instance;
    6     }
    7 }

    这种方式基于classloder机制避免了多线程的同步问题,不过,instance在类装载时就实例化,这时候初始化instance显然没有达到lazy loading的效果。不推荐。

    第四种,线程安全(饿汉模式)

     1 public class Singleton4 {
     2     private static Singleton4 instance ;
     3     static {
     4         instance = new Singleton4();
     5     }
     6     private Singleton4(){}
     7     public static synchronized Singleton4 getInstance(){
     8         return instance;
     9     }
    10 }

    等同于第三种

    第五种,线程安全(静态内部类)

    1 public class Singleton5 {
    2     private Singleton5(){}
    3     public static synchronized Singleton5 getInstance(){
    4         return SingletonHolder.instance;
    5     }
    6     private static class SingletonHolder{
    7         private static Singleton5 instance = new Singleton5();
    8     }
    9 }

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

    第六种,线程安全(枚举类)

    1 public enum Singleton6 {
    2     INSTANCE;
    3     public void whateverMethod(){}
    4 }

    这种方式是Effective Java作者Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,可谓是很坚强的壁垒啊,推荐!

    第七种,线程安全(双重校验模式)

     1 public class Singleton7 {
     2     private static Singleton7 instance;
     3     private Singleton7(){}
     4     public static synchronized Singleton7 getInstance(){
     5         if(instance == null){
     6             synchronized (Singleton7.class){
     7                 if(instance ==null){
     8                     instance = new Singleton7();
     9                 }
    10             }
    11         }
    12         return instance;
    13     }
    14 
    15 }

    最常用的一种。

    总结

    有两个问题需要注意:

         1、如果单例由不同的类装载器装入,那便有可能存在多个单例类的实例。假定不是远端存取,例如一些servlet容器对每个servlet使用完全不同的类  装载器,这样的话如果有两个servlet访问一个单例类,它们就都会有各自的实例。

         2、如果Singleton实现了java.io.Serializable接口,那么这个类的实例就可能被序列化和复原。不管怎样,如果你序列化一个单例类的对象,接下来复原多个那个对象,那你就会有多个单例类的实例。

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

    1  private static Class getClass(String classname) throws ClassNotFoundException {
    2         ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    3 
    4         if (classLoader == null)
    5             classLoader = Singleton.class.getClassLoader();
    6 
    7         return (classLoader.loadClass(classname));
    8     }

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

    重写readResolve()方法。防止反序列化获取多个对象的漏洞。  

    无论是实现Serializable接口,或是Externalizable接口,当从I/O流中读取对象时,readResolve()方法都会被调用到。  实际上就是用readResolve()中返回的对象直接替换在反序列化过程中创建的对象。  

  • 相关阅读:
    easy ui 表单ajax和from两种提交数据方法
    easy ui 下拉级联效果 ,下拉框绑定数据select控件
    easy ui 下拉框绑定数据select控件
    easy ui 异步上传文件,跨域
    easy ui 菜单和按钮(Menu and Button)
    HTTP 错误 404.3
    EXTJS4.2 后台管理菜单栏
    HTML 背景图片自适应
    easy ui 表单元素input控件后面加说明(红色)
    EXTJS 4.2 添加滚动条
  • 原文地址:https://www.cnblogs.com/foreverYoungCoder/p/7727937.html
Copyright © 2011-2022 走看看