关于单例模式(代码篇)

很早的时候,转发过一篇单例模式的文章: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);
     }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值