//方法没有同步,调用效率高
public static SingletonDome01 getInstance() {
return instance;
}
}
=============================================================================
要点: lazy load! 延迟加载, 懒加载! 真正用的时候才加载!
问题:资源利用率高了。但是,每次调用getInstance()方法都要同步,并发效率较低。
package com.ahzy;
/**
-
单例懒汉式
-
@author 晓宇码匠
-
资源利用率高。但是每次调用getIntance()都要同步,并发效率低
-
当创建实例的代价较大时,用懒汉式
*/
public class SingletonDome02 {
private static SingletonDome02 instance;
private SingletonDome02() {
}
//方法同步,调用效率低
public static synchronized SingletonDome02 getInstance(){
//延迟加载,懒加载,真正用的时候再加载
if(instance==null){
instance = new SingletonDome02();
}
return instance;
}
}
=====================================================================
要点:这个模式将同步内容下方到if内部,提高了执行的效率不必每次获取对象时都进行同步,只有第一次才同步创建了以后就没必要了。
问题: 由于编译器优化原因和JVM底层内部模型原因,偶尔会出问题。不建议使用。
package com.ahzy;
/**
-
单例双重检测锁模式
-
@author 晓宇码匠
-
问题:由于编译器优化原因和JVM底层模式内部原因,偶尔会出现数据调整问题,不建议使用
*/
public class SingletonDome03 {
private static SingletonDome03 instance = null;
private SingletonDome03() {}
/*
-
这个模式将同步内容下方到if内部,提高了执行的效率
-
不必每次获得对象时都要进行同步,只有第一次才同步
-
创建了以后就没必要了。
*/
public static SingletonDome03 getInstance() {
if (instance == null) {
SingletonDome03 sc;
synchronized (SingletonDome03.class) {
sc = instance;
if (sc == null) {
synchronized (SingletonDome03.class) {
if (sc == null) {
sc = new SingletonDome03();
}
}
instance=sc;
}
}
}
return instance;
}
}
==================================================================================
要点:
-
外部类没有static属性,则不会像饿汉式那样立即加载对象。
-
只有真正调用getInstance(),才会加载静态内部类。加载类时是线程 安全的。 instance是static final类型,保证了内存中只有这样一个实例存在,而且只能被赋值一次,从而保证了线程安全性。
-
兼备了并发高效调用和延迟加载的优势!
package com.ahzy;
/**
-
静态类部类(也是一种懒加载)
-
@author 晓宇码匠
-
特点:延迟加载,调用效率高,线程安全
*/
public class SingletonDome04 {
private static class SingletClassInstance{
private static SingletonDome04 instance = new SingletonDome04();
}
private SingletonDome04(){
}
public static SingletonDome04 getInstance(){
return SingletClassInstance.instance;
}
}
======================================================================
优点:
-
实现简单.
-
枚举本身就是单例模式。由JVM从根本上提供保障!避免通过反射和反序列化的漏洞!
缺点:无延迟加载.
package com.ahzy;
/**
-
单例枚举式
-
@author 晓宇码匠
-
优点:简单
-
缺点:没有延迟加载
*/
public enum SingletonDome05 {
//这个枚举元素,本身就是单例模式
INSTANCE;
//添加自己需要的操作
public void singletonOperation() {
}
}
================================================================
package com.ahzy;
public class Client {
public static void main(String[] args) {
SingletonDome01 s1 = SingletonDome01.getInstance();
SingletonDome01 s2 = SingletonDome01.getInstance();
System.out.println(s1);
System.out.println(s2);
System.out.println(SingletonDome05.INSTANCE==SingletonDome05.INSTANCE);
}
}
结果:
com.ahzy.SingletonDome01@15db9742
com.ahzy.SingletonDome01@15db9742
true
==================================================================
方法:反射和反序列化(不包含枚举式)
预防操作(这个一般会在开发jdk或一些jar包的时候会去用):
-
反射可以破解上面几种(不包含枚举式)实现方式!(可以在构造方法中手动抛出异常控制)
-
可以通过定义readResolve()防止获得不同对象。
-
反序列化时,如果对象所在类定义了readResolve(),(实际是一种回调),定义返回哪个对象。
public class SingletonDemo01 implements Serializable {
private static SingletonDemo01 s;
private SingletonDemo01() throws Exception {
if (s != null) {
throw new Exception(“只能创建一个对象”);
// 通过手动抛出异常,避免通过反射创建多个单例对象!
}
} // 私有化构造器
public static synchronized SingletonDemo01 getInstance() throws Exception {
if (s == null) {
s = new SingletonDemo01();
}
return s;
}
// 反序列化时,如果对象所在类定义了readResolve(),(实际是一种回调),定义返回哪个对象。
private Object readResolve() throws ObjectStreamException {
return s;
}
}
================================================================
- 效率