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

参考资料:

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. [资料]PHP Yaf

    QConShanghai2013-惠新宸-微博LAMP性能优化之路 Yaf-一个PHP扩展实现的PHP框架 Baidu Yaf

  2. Linux内核

    Linux内核配置.编译及Makefile简述 Hi,大家好!我是CrazyCatJack.最近在学习Linux内核的配置.编译及Makefile文件.今天总结一下学习成果,分享给大家^_^ 1.解压 ...

  3. [CareerCup] 1.7 Set Matrix Zeroes 矩阵赋零

    1.7 Write an algorithm such that if an element in an MxN matrix is 0, its entire row and column are ...

  4. [CareerCup] 9.2 Robot Moving 机器人移动

    9.2 Imagine a robot sitting on the upper left corner of an X by Y grid. The robot can only move in t ...

  5. Github克隆别人的库

    一. 首先在网站上进入别人的库(通过别人提供的链接或者自己在页面上查询),然后在右下方选择SSH,将链接复制下来. 二. 在你的电脑上新建一个与人家库名相同的文件夹,然后在文件夹上右击,在弹出菜单上选 ...

  6. IT男的”幸福”生活

    IT男的”幸福”生活 IT男的”幸福”生活"续1 IT男的”幸福”生活"续2  IT男的”幸福”生活"续3  IT男的”幸福”生活"续4  IT男的”幸福”生活 ...

  7. 在ubuntu server上安装沸腾时刻环境

    1. 安装php5.6 http://phpave.com/upgrade-to-php-56-on-ubuntu-1404-lts/ 按照这篇文章的顺序来做,可以安装最新5.6版本php 安装好了以 ...

  8. ThinkPHP之视图模版的使用

    用户发起一个请求后,服务器应该返回一个页面,而页面是由我们的视图层来控制的. 一.修改控制器 <?php namespace Home\Controller; use Think\Control ...

  9. Linq之IQueryable接口与IEnumberable区别

    IEnumerable接口 公开枚举器,该枚举器支持在指定类型的集合上进行简单迭代.也就是说:实现了此接口的object,就可以直接使用foreach遍历此object: IEnumerable 包含 ...

  10. 第二章:Javascript词法结构

    编程语言的词法结构是一套基础性的规则,用来描述你如何编写这门语言.作为语法的基础,它规定了变量名是怎么样的,如何写注释,以及语句之间是如何区分的.本节用很短的篇幅来介绍javascript的词法结构. ...