`
iamzhongyong
  • 浏览: 796425 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

关于单例模式(代码篇)

阅读更多

很早的时候,转发过一篇单例模式的文章:http://iamzhongyong.iteye.com/blog/1539642 

最近又翻了一本设计模式的书,然后发现单例其实也简单也复杂,于是就打算把代码敲一下,保存下来。

------------------------------------------------------------------------------------------------------

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package singleton;
/**
 * 最简单的单例模式
 */
public class SimpleSingleton {
 
    /**
     * 构造方法私有化,外部无法通过构造方法创建对象,这样能够屏蔽外部直接new
     * 还有就是反射了,反射时可以使用setAccessible方法来突破private的限制,
     * 我们需要做到第一点工作的同时,还需要在在ReflectPermission("suppressAccessChecks")
     * 权限下使用安全管理器(SecurityManager)的checkPermission方法来限制这种突破,
     * 一般来说,不会真的去做这些事情,都是通过应用服务器进行后台配置实现。
     * 再就是序列化了,序列化会在SimpleSerializableSingleton这个类中做介绍
     */
    private SimpleSingleton(){}
 
    /**
     * 类型是static,这样在JVM进行类加载的时候就会做类的实例化,JVM保证线程安全
     * 根据JLS(Java Language Specification)中的规定,一个类在一个ClassLoader中只会被初始化一次,
     * 这点是JVM本身保证的,那就把初始化实例的事情扔给JVM好了
     */
    private static final SimpleSingleton instance = new SimpleSingleton();
 
    //通过一个静态方法,获得这个对象
    public static SimpleSingleton getInstance(){
        return instance;
    }
}

 

 

 

------------------------------------------------------------------------------------------------------

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package singleton;
/**
 * 单例模式的懒加载策略,不在类加载的时候进行实例化,而是在第一次调用的时候进行
 */
public class SimpleLazySingleton {
 
    //私有构造方法
    private SimpleLazySingleton(){}
 
    //在类加载的时候,这个对象不进行实例化,volatile变量,拥有可见性
    private static volatile SimpleLazySingleton instance = null;
 
    /**
     * @deprecated
     * 这种会有线程安全问题,因为可能存在多线程访问这个方法,这个时候对象就有可能不是单例的
     */
    public static SimpleLazySingleton getInstanceNotSafe(){
        if(instance == null){
            instance = new SimpleLazySingleton();
        }
        return instance;
    }
 
    /**
     * @deprecated
     * 做一个简单的处理,就是在getInstance的时候添加锁关键字
     * 但是这样有个问题,就是所有的getInstance操作全部加锁,性能会下降很多
     */
    public static synchronized SimpleLazySingleton getInstanceSyncSafe(){
        if(instance == null){
            instance = new SimpleLazySingleton();
        }
        return instance;
    }
 
    /**
     * @deprecated
     * 那就做锁的细化吧,把锁的处理挪到方法体内部,仅仅在instance为空的时候,再去加锁
     */
    public static SimpleLazySingleton getInstanceSyncNotSafe(){
        if(instance == null){
            synchronized (SimpleLazySingleton.class) {
                instance = new SimpleLazySingleton();
            }
        }
        return instance;
    }
 
    /**
     * 那就做锁的细化吧,把锁的处理挪到方法体内部,仅仅在instance为空的时候,再去加锁
     */
    public static SimpleLazySingleton getInstance(){
        if(instance == null){
            synchronized (SimpleLazySingleton.class) {
                /**
                 * 这里称之为double-check-lock,为啥要做这不操作呢?
                 * 因为可能有多个线程进入第一个“if(instance == null)”,这个时候,线程去强占锁,
                 * 抢到锁的线程进行instance的初始化操作,完了之后释放锁,
                 * 第二个线程获得锁,这个时候进入之后,如果没有判空操作,会再一次初始化了实例,这时候就不是单例了
                 */
                if(instance == null){
                    instance = new SimpleLazySingleton();
                }
            }
        }
        return instance;
    }
}

------------------------------------------------------------------------------------------------------

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package singleton;
 
/**
 * 通过Holder的形式来进行,利用JVM的机制来保障线程安全
 */
public class SimpleHolderSingleton {
 
    //私有化
    private SimpleHolderSingleton(){}
 
    //类中有一个私有的XXXHolder类,这个因为是static类型的,所以在JVM加载类的时候就会加载到,但是INSTANCE就不会
    private static class SimpleHolderSingletonHolder{
        //持有外部类的属性
        static final SimpleHolderSingleton INSTANCE = new SimpleHolderSingleton();
    }
 
    //这样会在第一次调用的时候进行初始化操作,因为INSTANCE是static的,所以借助了JVM的机制来保障线程安全
    public static SimpleHolderSingleton getInstance(){
        return SimpleHolderSingletonHolder.INSTANCE;
    }
}

 

 

------------------------------------------------------------------------------------------------------

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package singleton;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
 
/**
 * 如果单例的类实现了序列化接口,这个时候需要做一下特殊处理,
 */
public class SimpleSerializableSingleton implements java.io.Serializable{
 
    private static final long serialVersionUID = -589503673156379879L;
 
    //屏蔽外部new的实例化
    private SimpleSerializableSingleton(){}
 
    private static SimpleSerializableSingleton instance = new SimpleSerializableSingleton();
 
    public static SimpleSerializableSingleton getInstance(){
        return instance;
    }
 
    /**
     * 这个方法,会在发序列化构建对象的时候调用到,如果不这么处理
     * 反序列化之后的对象,是另外一个内存地址,也就是说不再是单例的了
     */
    private Object readResolve() {
        System.out.println("readResolve,被调用了");
        return getInstance(); 
    
 
    public static void main(String[] args) throws Exception {
        SimpleSerializableSingleton simple = SimpleSerializableSingleton.getInstance();
        //获得单例对象的内存地址
        System.out.println(simple);
        //定义序列化写入的文件
        File file = new File("d:\\git\\serializable");
        //构造objectOutputStream
        ObjectOutputStream outStream = new ObjectOutputStream(new FileOutputStream(file));
        //写入对象
        outStream.writeObject(simple);
        outStream.close();
 
        //反序列化
        ObjectInputStream inStream = new ObjectInputStream(new FileInputStream(file));
        SimpleSerializableSingleton simpeFromSeria = (SimpleSerializableSingleton)inStream.readObject();
        System.out.println(simpeFromSeria);
        inStream.close();
    }
 
}

------------------------------------------------------------------------------------------------------

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package singleton;
 
import java.lang.reflect.ReflectPermission;
import java.security.Permission;
/**
 * 如何禁止外部通过反射来做单例对象的序列化
 */
public class SimpleReflectionSingleton {
     
    private SimpleReflectionSingleton(){}
     
    private static SimpleReflectionSingleton instance = new SimpleReflectionSingleton();
     
    public static SimpleReflectionSingleton getInstance(){
        return instance;
    }
    public static void main(String[] args) throws Exception{
         
        //启动JVM的安全检察,在进行反射校验的时候,判断一下是否是“singleton”,如果是,就禁止反射
        System.setSecurityManager(new SecurityManager(){
            @Override
            public void checkPermission(Permission perm) {
                if (perm instanceof ReflectPermission && "suppressAccessChecks".equals(perm.getName())) {
                     for (StackTraceElement elem : Thread.currentThread().getStackTrace()) {
                          if (elem.getClassName().endsWith("Singleton")) {
                              throw new SecurityException();
                          }
                     }
                 }
            }
        });
         
        SimpleReflectionSingleton simple = SimpleReflectionSingleton.getInstance();
        System.out.println(simple);
         
        Class<?> clazz = SimpleReflectionSingleton.class;
         
        SimpleReflectionSingleton ref = (SimpleReflectionSingleton)clazz.newInstance();
         
        System.out.println(ref);
    }
}

3
2
分享到:
评论
4 楼 851228082 2015-04-22  
这是我见过最全面的介绍单例模式的code了。赞!
3 楼 在世界的中心呼喚愛 2014-04-24  
iamzhongyong 写道
last_forever 写道
这个
//类中有一个私有的XXXHolder类,这个因为是static类型的,所以在JVM加载类的时候就会加载到,但是INSTANCE就不会
    private static class SimpleHolderSingletonHolder{
        //持有外部类的属性
        static final SimpleHolderSingleton INSTANCE = new SimpleHolderSingleton();
    }

与这个
private static final SimpleSingleton instance = new SimpleSingleton();


有什么区别呢

第二个是在加载这个类的时候就初始化了。
第一个的话,SimpleHolderSingletonHolder因为是static的,所以在加载的时候会加载进来,但是里面的属性,会在用到的时候才加载,是一种懒加载的模式,通过JVM加载类的机制来保证线程安全的


static 和final会直接读取变量或者对象(我记得随机数不行)
static只是加载class类,需要的时候才会初始化class
2 楼 iamzhongyong 2014-04-23  
last_forever 写道
这个
//类中有一个私有的XXXHolder类,这个因为是static类型的,所以在JVM加载类的时候就会加载到,但是INSTANCE就不会
    private static class SimpleHolderSingletonHolder{
        //持有外部类的属性
        static final SimpleHolderSingleton INSTANCE = new SimpleHolderSingleton();
    }

与这个
private static final SimpleSingleton instance = new SimpleSingleton();


有什么区别呢

第二个是在加载这个类的时候就初始化了。
第一个的话,SimpleHolderSingletonHolder因为是static的,所以在加载的时候会加载进来,但是里面的属性,会在用到的时候才加载,是一种懒加载的模式,通过JVM加载类的机制来保证线程安全的
1 楼 last_forever 2014-04-23  
这个
//类中有一个私有的XXXHolder类,这个因为是static类型的,所以在JVM加载类的时候就会加载到,但是INSTANCE就不会
    private static class SimpleHolderSingletonHolder{
        //持有外部类的属性
        static final SimpleHolderSingleton INSTANCE = new SimpleHolderSingleton();
    }

与这个
private static final SimpleSingleton instance = new SimpleSingleton();


有什么区别呢

相关推荐

    JS 设计模式之:单例模式定义与实现方法浅析

    本文实例讲述了JS 设计模式之:单例模式定义与实现方法。分享给大家供大家参考,具体如下: 良好的设计模式可以显著提高代码的可读性,降低复杂度和维护成本。笔者打算通过几篇文章通俗地讲一讲常见的或者实用的设计...

    –设计模式–五种实现单例模式的方式

    ① 应用场景实例② 模式优点③ 模式缺点④ 注意事项■ 单例模式的五种实现方式饿汉式代码实现懒加载代码实现双重检测锁代码实现静态内部类代码实现(也是懒加载的一种方式)枚举代码实现:diamond_suit: 总结 ...

    单例模式简介以及C++版本的实现

    本篇博文主要内容参考 C++的单例模式一文,在此,为原作者耐心细致的分析讲解,表示感谢。本文将结合此篇文章,给出自己做实验后的理解以及代码,作为学习的小结。  单例模式,它的意图是保证一个类仅拥有一个实例...

    php单例模式详细介绍及实现

    这篇文章主要介绍了PHP中数据库单例模式的实现代码分享,本文先是讲解了单例模式的一些知识,然后给出了数据库单例模式实现代码。 什么是单例模式 单例模式顾名思义,就是只有一个实例。 作为对象的创建模式, 单例...

    利用ES6实现单例模式及其应用详解

    单例是在程序设计非常基础的东西,这篇文章主要给大家介绍了关于利用ES6实现单例模式及其应用的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧。

    浅析php单例模式

    本系列文章来总结一下设计模式在PHP中的应用,这是第一篇创建型模式之单例模式。 一、设计模式简介 首先我们来认识一下什么是设计模式: 设计模式是一套被反复使用、容易被他人理解的、可靠的代码设计经验的总结。 ...

    软件设计模式与体系结构(讲解+代码)

     【例2.6】单例模式-互联网连接  【例3.2】组合模式-五子棋代码  【例3.3】组合模式-空军指挥系统  【例3.4】组合模式-世界问候语  【例3.7】类适配器模式-客户信息验证  【例3.8】对象适配器模式-字符...

    C++实现一个线程安全的单例工厂实现代码

    C++实现一个线程安全的单例工厂实现代码 我们见到经常有人用 static 局部对象的方式实现了类似单例模式,最近发现一篇文章明确写明 编译器在处理 static局部变量的时候 并不是线程安全的 !!! ...

    深入理解Java中没那么简单的单例模式

    主要给大家详细介绍了Java单例模式,关于Java中的单例模式并非看起来那么简单的,为什么要这么说呢?下面通过这篇文章来一起看看吧,有需要的朋友们可以参考借鉴。

    Android也架构之三:简单工厂模式优化网络请求

    拥抱变化,让我们冲现在开始吧,上一篇文章《Android也架构之二:单例模式访问网络》中,我们学会用了单例模式,单例模式一般解决的是和程序相关的问题,和业务逻辑无关,今天开始,我们就开始学习和业务相关的设计...

    体系结构学习代码!特别详细丰富

     【例2.6】单例模式-互联网连接  【例3.2】组合模式-五子棋代码  【例3.3】组合模式-空军指挥系统  【例3.4】组合模式-世界问候语  【例3.7】类适配器模式-客户信息验证  【例3.8】对象适配器模式-字符...

    python单例设计模式实现解析

    这篇文章主要介绍了python单例设计模式实现解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 所谓单例,就是让类创建对象的时候,在系统中只有唯一的一个...

    Android代码-java-bible

    如何正确地写出单例模式 代理模式剖析 什么是策略模式 Java8系列 Java8简明教程 Java8 Foreach Hexo搭建博客 分分钟部署一个Hexo环境 各种配置详解 开始写作吧 开发者指南 git - 简明指南 Jersey-2.x用户指南...

    Java实验1代码.doc

    本专栏主要为Java程序设计(基础)实验报告和Java程序设计(进阶)...进阶篇有反射、泛型、注解、网络编程、多线程、序列化、数据库、Servlet、JSP、XML解析、单例模式与枚举。本专栏主要为Java入门者提供实验参考。

    Delphi 深度探索(第二版)〖含随书光盘源代码〗

    6.1.2 单例模式(singleton) 6.1.3 建造模式(builder) 6.1.4 原型模式(prototype) 6.2 结构模式 6.2.1 适配器模式(adapter) 6.2.2 合成模式(composite模式) 6.2.3 装饰模式(decorator模式) ...

    深入理解JavaScript系列.chm

    25.设计模式之单例模式 26.设计模式之构造函数模式 27.设计模式之建造者模式 28.设计模式之工厂模式 29.设计模式之装饰者模式 30.设计模式之外观模式 31.设计模式之代理模式 32.设计模式之观察者模式 33.设计模式之...

    Swift中定义单例的方法实例

    Swift中单例的写法有很多种,下面这篇文章主要给大家介绍了关于Swift中定义单例的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习...

    深入理解JavaScript系列(.chm)

    深入理解JavaScript系列(25):设计模式之单例模式 深入理解JavaScript系列(26):设计模式之构造函数模式 深入理解JavaScript系列(27):设计模式之建造者模式 深入理解JavaScript系列(28):设计模式之工厂...

    深入理解JavaScript系列

    深入理解JavaScript系列(25):设计模式之单例模式 深入理解JavaScript系列(26):设计模式之构造函数模式 深入理解JavaScript系列(27):设计模式之建造者模式 深入理解JavaScript系列(28):设计模式之工厂...

    PHP实现的数据对象映射模式详解

    数据库连接文件Db.php(如果没有可以到前面一篇《PHP单例模式数据库连接类与页面静态化》里面找) 自动加载类文件Config.php(如果没有可以去上一篇《PHP策略模式》里拿过来) 入口文件DataUser.php &lt;?php ...

Global site tag (gtag.js) - Google Analytics