单例模式的优点:
要点: 饿汉式单例模式代码中,static变量会在类装载时初始化,此时也不会涉及多个线程对象访问该对象的问题。虚拟机保证只会装载一次该类,肯定不会发生并发访问的问题。因此,可以省略synchronized关键字。 问题:如果只是加载本类,而不是要调用getInstance(),甚至永远没有调用,则会造成资源浪费!
package com.ahzy;
/** * 单例饿汉式 * @author 晓宇码匠 * 频繁的调用这个实例的时候用饿汉式 */
public class SingletonDome01 {
//类初始化时加载这个对象,没有延迟加载的优势,加载类时,是天然的线程安全
private static SingletonDome01 instance = new SingletonDome01();
//私有化构造器
private SingletonDome01(){
}
//方法没有同步,调用效率高
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;
}
}
要点:
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;
}
}
优点:
缺点:无延迟加载.
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包的时候会去用):
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;
}
}
模式 | 时间 |
---|---|
饿汉式 | 22ms |
静态内部类式 | 28ms |
枚举式 | 32ms |
双重检查锁式 | 65ms |
懒汉式 | 636ms |
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/106710.html原文链接:https://javaforall.cn