Java单例模式解析

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;
    }
}
 
 
 
------------------------------------------------------------------------------------------------------

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;
    }
}
------------------------------------------------------------------------------------------------------
 

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;
    }
}
 
 
------------------------------------------------------------------------------------------------------

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();
    }
 
}
------------------------------------------------------------------------------------------------------

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
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值