Java单例模式解析
2014-04-23 18:06
369 查看
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); } }
相关文章推荐
- Java单例模式解析
- 实例解析Java单例模式编程中对抽象工厂模式的运用
- Java疑惑点解析(一)
- xml有哪些解析技术?区别是什么?
- 用mysql源码进行SQL解析
- 骨骼蒙皮动画(Skinned Mesh)的原理解析(转)
- 新手必看——Windows Phone 7.5 手机全解析(非开发技术帖)
- parse_url()解析url
- JavaScript 全面解析各种浏览器网页中的JS 执行顺序
- json解析
- AJAX解析XML实例之下拉框省、市二级联动
- 98. IP数据包解析 题目1475:IP数据包解析
- Android xml 解析
- dom解析和sax解析
- [SAP ABAP开发技术总结]ABAP读写、解析XML文件
- Oracle数据库实例核心技术解析_超越OCP精通Oracle视频教程培训05
- Linux2.6 内核的 Initrd 机制解析
- 用XPATH解析网页并抓取要的内容
- js解析GET参数解析一次性解决
- iOS项目之解析HTML数据