关于Java单例
线程安全、延迟加载、序列化反序列化反射安全
参考资料:
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单例的更多相关文章
- java单例的几种实现方法
java单例的几种实现方法: 方式1: public class Something { private Something() {} private static class LazyHolder ...
- java单例类/
java单例类 一个类只能创建一个实例,那么这个类就是一个单例类 可以重写toString方法 输出想要输出的内容 可以重写equcal来比较想要比较的内容是否相等 对于final修饰的成员变量 一 ...
- java单例-积木系列
一步步知识点归纳吧,把以前似懂非懂,了解表面,知道点不知道面的知识归一下档. 懒汉式单例: 私有化构造函数,阻止外界实例话对象,调用getInstance静态方法,判断是否已经实例化. 为什么是懒 ...
- Java单例类的简单实现
对于java新手来说,单例类给我的印象挺深,之前一道web后台笔试题就是写单例类.*.*可惜当时不了解. 在大部分时候,我们将类的构造器定义成public访问权限,允许任何类自由创建该类的对象.但在某 ...
- 【Java学习笔记之三十】详解Java单例(Singleton)模式
概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...
- 转:java单例设计模式
本文转自:http://www.cnblogs.com/yinxiaoqiexuxing/p/5605338.html 单例设计模式 Singleton是一种创建型模式,指某个类采用Singleton ...
- 熟悉的味道——从Java单例写到C++单例
设计模式中,单例模式是常见的一种.单例模式需要满足以下两个条件: 保证一个类只能创建一个示例: 提供对该实例的全局访问点. 关于单例最经典的问题就是DCL(Double-Checked Lock),今 ...
- java单例五种实现模式梳理
java单例五种实现模式 饿汉式(线程安全,调用效率高,但是不能延时加载) 一上来就把单例对象创建出来了,要用的时候直接返回即可,这种可以说是单例模式中最简单的一种实现方式.但是问题也比较明显.单例在 ...
- JAVA单例实现方式(常用)
JAVA单例实现方式(常用) public class Singleton { // Q1:为什么要使用volatile关键字? private volatile static Singleton u ...
- Java单例设计模式的实现
1. 单例设计模式的定义 单例设计模式确保类只有一个实例对象,类本身负责创建自己的对象并向整个系统提供这个实例.在访问这个对象的时候,访问者可以直接获取到这个唯一对象而不必由访问者进行实例化. 单例设 ...
随机推荐
- usb驱动开发2之代码地图
USB只是Linux庞大家族里的一个小部落,host controller是它们的族长,族里的每个USB设备都需要被系统识别.下图显示包含一个USB接口的USB鼠标导出的结果. USB系统中的第一个U ...
- mousewheel 模拟滚动
div{ box-sizing:border-box; } .father{ width:500px; height:400px; margin:auto; margin-top: 50px; bor ...
- C++的CreateThread实例
function CreateThread( lpThreadAttributes: Pointer; {安全设置} dwStackSize: DWORD; ...
- OAViewObject中clearCache(),reset(),setMaxFetchSize(-1)的使用
今天在页面跳转之后,明明执行了查询,且查询语句正确的情况下,页面不显示数据,且点击SubmitButton包浏览器后退异常. 代码如下: OAViewObjectImpl vo=(OAViewObje ...
- Java Concurrency in Practice 读书笔记 第十章
粗略看完<Java Concurrency in Practice>这部书,确实是多线程/并发编程的一本好书.里面对各种并发的技术解释得比较透彻,虽然是面向Java的,但很多概念在其他语言 ...
- 那么小伙伴么,问题来了,WPF中,控件的Width="*"在后台怎么写?
用到DataGrid的列是自动生成的,但是大家都知道,WPF的DataGrid会在最后多出一列,通常的解决办法都是在最后一列的列宽上这样设置 Width="*",这样,最后一列多出 ...
- OpenCV Start
开始学习opencv了. 从官网下载了 opencv-3.0.0-alpha.exe(windows版本) opencv-3.0.0-alpha.zip (linux版本) 从windows版本的安装 ...
- ThreadLocal详解
ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量. 这个玩意有什么用处,或者说为什么要有这么一个东东?先解释一下,在并发编程的时候,成员变量如果不做任何处理其实是线程不安全的,各个线 ...
- 通通的最后一篇博客(附自制html5平面射击小游戏一枚)
这是我最后一篇博客了,由于本人的人生规划吧,以后应该也写不出什么好的技术文章了,到现在在博客园写了2年, 今天一看,我也有了120个粉丝,好几万的浏览量,感谢大家的支持啊~~ 半年没有写博客了,由于半 ...
- .NET MVC控制器向视图传递数据的四种方式
.NET MVC控制器向视图传递数据的四种方式: 1.ViewBag ViewBag.Mvc="mvc"; 2.ViewData ViewBag["Mvc"] ...