线程安全、延迟加载、序列化反序列化反射安全

参考资料:

http://blog.csdn.net/haoel/article/details/4028232

public class SingletonTest implements Runnable {
static SingletonClass1 instance = null; public static void main(String args[]) {
// SingletonClass0 instance = new SingletonClass0();// The constructor
// SingletonClass0() is not visible for (int i = 0; i < 15; i++) {
new Thread(new SingletonTest()).start();
}
// System.out.println(instance.getClass()); } @Override
public void run() {
// TODO Auto-generated method stub
SingletonClass6.getInstance();
// System.out.println(SingletonClass7.instance.hashCode());
}
} class SingletonClass0 {
private static SingletonClass0 instance = null; private SingletonClass0() {
System.out.println("constructor run");
} public static SingletonClass0 getInstance() {// wrong 单线才单线程下没问题,多线程下仍会有多个实例
if (instance == null) {
instance = new SingletonClass0();
System.out.println(instance.hashCode());
}
return instance;
}
} class SingletonClass1 {
private static SingletonClass1 instance = null; private SingletonClass1() {
System.out.println("constructor run");
} public static SingletonClass1 getInstance() {// wrong 多线程下仍会有多个实例,与上一种
// 区别在于过个线程的new过程被同步了
if (instance == null) {
synchronized (SingletonClass1.class) {
instance = new SingletonClass1();
System.out.println(instance.hashCode());
}
}
return instance;
}
} class SingletonClass2 {
private static SingletonClass2 instance = null; private SingletonClass2() {
System.out.println("constructor run");
} public static SingletonClass2 getInstance() {
synchronized (SingletonClass2.class) {// right。只会有一个线程new实例,但阻碍了后续线程读实例
if (instance == null) {
instance = new SingletonClass2();
System.out.println(instance.hashCode());
}
}
return instance;
}
} class SingletonClass3 {
private static SingletonClass3 instance = null; private SingletonClass3() {
System.out.println("constructor run");
} public static SingletonClass3 getInstance() {
synchronized (SingletonClass3.class) {// right
// 只会有一个线程new实例,不会影响后续线程读实例,但instance=new
// SingletonClass3()在JVM内不是原子操作,内部的几个步骤可能乱序,从而出错
if (instance == null) {
synchronized (SingletonClass1.class) {
if (instance == null) {
instance = new SingletonClass3();
System.out.println(instance.hashCode());
}
}
}
}
return instance;
}
} class SingletonClass4 {
private static volatile SingletonClass4 instance = null;// right
// 只有一个实例,volatite保证了在JVM内部new
// instance的几个操作禁止指令重排序优化 private SingletonClass4() {
System.out.println("constructor run");
} public static SingletonClass4 getInstance() {
synchronized (SingletonClass4.class) {
if (instance == null) {
synchronized (SingletonClass1.class) {
if (instance == null) {
instance = new SingletonClass4();
System.out.println(instance.hashCode());
}
}
}
}
return instance;
}
} class SingletonClass5 {// right,但是由类加载器在类加载时创建实例,我们无法控制实例创建的时机以干一些事(比如某个配置文件,或是某个被其它类创建的资源)
public volatile static SingletonClass5 instance = new SingletonClass5(); private SingletonClass5() {
System.out.println("constructor run");
}; public static SingletonClass5 getInstance() {
System.out.println(instance.hashCode());
return instance;
}
} class SingletonClass6 {// 仍然使用JVM本身机制保证了线程安全问题;由于 SingletonHolder 是私有的,除了
// getInstance()
// 之外没有办法访问它,因此它只有在getInstance()被调用时才会真正创建;同时读取实例的时候不会进行同步,没有性能缺陷;也不依赖
// JDK 版本
private static class SingletonHolder {
private static final SingletonClass6 INSTANCE = new SingletonClass6();
} private SingletonClass6() {
System.out.println("constructor run");
} public static final SingletonClass6 getInstance() {
System.out.println(SingletonHolder.INSTANCE.hashCode());
return SingletonHolder.INSTANCE;
}
} class SingletonClass7 {
public SingletonClass7() {
System.out.println("constructor run");
}
} enum SingletonClass {
instance;
}

http://mp.weixin.qq.com/s/q7-GWt87S7uJ9NY-s1z4SA

需要参数:懒汉式1。(线程安全改进3、需要才new改进4)

不需要参数:饿汉式2。(本身线程安全、需要才new改进5)

上述几种实现方式都存在反射、序列化、反序列化使得单例被破坏的问题,可能成为漏洞被利用,虽可采用手段加以解决(解决方式见下)但不简单高效(若单例类维持了其他对象的状态时还需要使他们成为transient的对象,此时就更复杂了)  ->  使用枚举6。

反序列化时单例被破坏的解决方法:readResolve

public class Singleton implements java.io.Serializable {
public static Singleton INSTANCE = new Singleton(); protected Singleton() {
} //反序列时直接返回当前INSTANCE
private Object readResolve() {
return INSTANCE;
}
}

反射时单例被破坏的解决方法:修改构造器,让它在创建第二个实例的时候抛异常

public static Singleton INSTANCE = new Singleton();
private static volatile boolean flag = true;
private Singleton(){
if(flag){
flag = false;
}else{
throw new RuntimeException("The instance already exists !");
}
}

1、

2、

3、

4、双_锁检测(DCL),JDK1.5之前volatile不能完全避免指令重排序优化,直到1.5才修复。因此JDK1.5之前Java中无法安全地使用DCL来实现单例模式。

5、

6、

枚举类实际上就是一个继承Enum类的类。

使用枚举单例的写法,我们完全不用考虑序列化和反射的问题。枚举序列化是由jvm保证的,每一个枚举类型和定义的枚举变量在JVM中都是唯一的,在枚举类型的序列化和反序列化上,Java做了特殊的规定:在序列化时Java仅仅是将枚举对象的name属性输出到结果中,反序列化的时候则是通过java.lang.Enum的valueOf方法来根据名字查找枚举对象。同时,编译器是不允许任何对这种序列化机制的定制的并禁用了writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法,从而保证了枚举实例的唯一性。

在单例中,枚举也不是万能的。在android开发中,内存优化是个大块头,而使用枚举时占用的内存常常是静态变量的两倍还多,因此android官方在内存优化方面给出的建议是尽量避免在android中使用enum。

更多关于枚举可以见:Java小计-枚举

关于Java单例的更多相关文章

  1. java单例的几种实现方法

    java单例的几种实现方法: 方式1: public class Something { private Something() {} private static class LazyHolder ...

  2. java单例类/

    java单例类  一个类只能创建一个实例,那么这个类就是一个单例类 可以重写toString方法 输出想要输出的内容 可以重写equcal来比较想要比较的内容是否相等 对于final修饰的成员变量 一 ...

  3. java单例-积木系列

    一步步知识点归纳吧,把以前似懂非懂,了解表面,知道点不知道面的知识归一下档.   懒汉式单例: 私有化构造函数,阻止外界实例话对象,调用getInstance静态方法,判断是否已经实例化. 为什么是懒 ...

  4. Java单例类的简单实现

    对于java新手来说,单例类给我的印象挺深,之前一道web后台笔试题就是写单例类.*.*可惜当时不了解. 在大部分时候,我们将类的构造器定义成public访问权限,允许任何类自由创建该类的对象.但在某 ...

  5. 【Java学习笔记之三十】详解Java单例(Singleton)模式

    概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...

  6. 转:java单例设计模式

    本文转自:http://www.cnblogs.com/yinxiaoqiexuxing/p/5605338.html 单例设计模式 Singleton是一种创建型模式,指某个类采用Singleton ...

  7. 熟悉的味道——从Java单例写到C++单例

    设计模式中,单例模式是常见的一种.单例模式需要满足以下两个条件: 保证一个类只能创建一个示例: 提供对该实例的全局访问点. 关于单例最经典的问题就是DCL(Double-Checked Lock),今 ...

  8. java单例五种实现模式梳理

    java单例五种实现模式 饿汉式(线程安全,调用效率高,但是不能延时加载) 一上来就把单例对象创建出来了,要用的时候直接返回即可,这种可以说是单例模式中最简单的一种实现方式.但是问题也比较明显.单例在 ...

  9. JAVA单例实现方式(常用)

    JAVA单例实现方式(常用) public class Singleton { // Q1:为什么要使用volatile关键字? private volatile static Singleton u ...

  10. Java单例设计模式的实现

    1. 单例设计模式的定义 单例设计模式确保类只有一个实例对象,类本身负责创建自己的对象并向整个系统提供这个实例.在访问这个对象的时候,访问者可以直接获取到这个唯一对象而不必由访问者进行实例化. 单例设 ...

随机推荐

  1. ab压测&htop工具

    1,apache bech 参考: http://www.nginx.cn/110.html http://www.ha97.com/4617.html ===================== y ...

  2. C#文件和文件文件夹按时间、名称排序-顺序与倒序

    对于文件和文件夹有多种排序方式,常用的就是按创建或修改时间.按文件名排序.在 C# 中,按时间和文件名排序都十分简单,用数组提供的排序方法 Array.Sort() 一行代码就可以搞定,当然也可以用常 ...

  3. 处理程序“ExtensionlessUrlHandler-Integrated-4.0”在其模块列表

    IIS上部署MVC网站,打开后ExtensionlessUrlHandler-Integrated-4.0解决办法 IIS上部署MVC网站,打开后ExtensionlessUrlHandler-Int ...

  4. 北京联想招聘-IOS高级 加入qq 群:220486180 或者直接在此 留言咨询

    ios 高级开发 Job ID #: 47980 Position Title: 高级iOS development engineer Location: CHN-Beijing Functional ...

  5. LeetCode:Clone Graph

    题目如下:实现克隆图的算法  题目链接 Clone an undirected graph. Each node in the graph contains a label and a list of ...

  6. java资源下载之官网地址

    [一].json下载地址 http://sourceforge.net/projects/json-lib/files/ [二].apache-commons下载地址 http://commons.a ...

  7. model的封装+MJExtension 方便后续处理

    //  基本模型 #import <Foundation/Foundation.h> @interface BasicDataModel : NSObject - (id)initWith ...

  8. ios 解析html

    xml,json都有大量的库来解析,我们如何解析html呢? TFHpple是一个小型的封装,可以用来解析html,它是对libxml的封装,语法是xpath.今天我看到一个直接用libxml来解析h ...

  9. 20145222黄亚奇《Java程序设计》第10周学习总结

    20145222 <Java程序设计>第10周学习总结 学习总结 网络编程 网络编程就是在两个或两个以上的设备(例如计算机)之间传输数据.程序员所作的事情就是把数据发送到指定的位置,或者接 ...

  10. JQuery上传文件插件Uploadify使用笔记

    新工作的第一份任务就是给实现 限制Uploadify 上传文件格式为图片 测试出来报错,选择了非图片文件,提示错误后,再选择其他文件,上传时还是包含了之前清空的非图片文件 最后实现效果的代码是 //上 ...