Java设计模式——单例模式

1、什么是单例模式。

确保某一个类只有一个实例,并且提供一个全局访问点。
简单来说,就是只能有一个实例。且该类需自行创建这个实例,并对其他类提供调用这一实例的方法。
它是Java中常用的设计模式

  • 特点

1.有且只有一个实例。
2.自我实例化。
3.提供全局访问方法。

  • 优点

有且只有一个实例,节约了内存资源,提高了系统形同。

  • 缺点

1.没有抽象层,不能扩展。
2.责任过重,违背了单一性原则。

吐槽:知识点吧,不记不背也不行,面试的时候考你要是说不上来,面上也过去。你看的烦躁,我写的也烦躁!啧啧啧!

2、单例设计的几种实现方式。

这个吧,几乎面试应该问到吧,我也好久没面试了,啧啧啧不太了解,有面试的小伙伴知道的可以评论和大家说说。

2.1、懒汉式

在第一次调用的时候才去实例化本身。
在并发条件下,可能出现多个实例化本身的对象,所以它是线程不安全的。

吐槽:因为它本身就懒,和我一样,所以不是程序运行就实例化,而是每次调用的时候才去实例化。

  1. 线程不安全
package com.cp.xiaobaibai;

/**
 * 描述: 单例模式——懒汉式——线程不安全
 * 创建人:cp小白白
 * 创建时间:2022/11/17 15:55
 */
public class SingletonLazyUnsafe {

    /**
     * 实例化,不懂得可以可以去网上查查
     * 无参构造一般都是public,这里使用private,防止用户主动创建实例
     * 你可以看看自己写的代码,无参构造是否是public(idea工具下alt+insert,选择Constructor)
     */
    private SingletonLazyUnsafe() {
    	System.out.println("我是不安全滴懒汉式单例设计模式");
    }
    /**
     * 这里不懂static的也去看一下基础吧。
     */
    private static SingletonLazyUnsafe singletonLazyUnsafe = null;

    /**
     * 获取SingletonLazyUnsafe实例,也叫静态工厂方法(不知道哪期会讲,看更新速度吧,毕竟我也是小白,也要上班)
     * getter方法就不多讲了。
     * @return SingletonLazyUnsafe
     */
    public static SingletonLazyUnsafe getSingletonLazyUnsafe() {
        // singletonLazyUnsafe为空的时候创建它,反之直接返回,保证了唯一性
        if (singletonLazyUnsafe == null) {
            singletonLazyUnsafe = new SingletonLazyUnsafe();
        }
        return singletonLazyUnsafe;
    }
}

测试类

package com.cp.xiaobaibai;

/**
 * 描述: 单例模式测试类
 * 创建人:cp小白白
 * 创建时间:2022/11/17 17:17
 */
public class Singleton {
	public static void main(String[] args) {
		// 懒汉式不安全单例设计模式测试
		SingletonLazyUnsafe singletonLazyUnsafe1 = SingletonLazyUnsafe.getSingletonLazyUnsafe();
		SingletonLazyUnsafe singletonLazyUnsafe2 = SingletonLazyUnsafe.getSingletonLazyUnsafe();
		System.out.println(singletonLazyUnsafe1 == singletonLazyUnsafe2);
		System.out.println(singletonLazyUnsafe1);
		System.out.println(singletonLazyUnsafe2);
	}
}

运行结果

我是不安全滴懒汉式单例设计模式
true
com.cp.xiaobaibai.SingletonLazyUnsafe@1b6d3586
com.cp.xiaobaibai.SingletonLazyUnsafe@1b6d3586

  1. 线程安全
package com.cp.xiaobaibai;

/**
 * 描述: 单例模式——懒汉式——线程安全
 * 实际上就是在getSingletonLazySafe方法上加入synchronized的同步
 * 创建人:cp小白白
 * 创建时间:2022/11/17 16:49
 */
public class SingletonLazySafe {

    private SingletonLazySafe() {
        System.out.println("我是安全滴懒汉式单例设计模式");
    }

	private static SingletonLazySafe singletonLazySafe = null;
	
	/**
	 * 获取SingletonLazySafe实例
	 * @return SingletonLazySafe
	 */
	 public static synchronized SingletonLazySafe getSingletonLazySafe() {
	 	if(singletonLazySafe == null) {
	 		singletonLazySafe = new SingletonLazySafe();
	 	}
		return singletonLazySafe;
	}
}

测试类

package com.cp.xiaobaibai;

/**
 * 描述: 单例模式测试类
 * 创建人:cp小白白
 * 创建时间:2022/11/17 17:17
 */
public class Singleton {
	public static void main(String[] args) {
		// 懒汉式不安全安全单例设计模式测试
		/* ...... */
		// 懒汉式安全单例设计模式测试
		SingletonLazySafe singletonLazySafe1 = SingletonLazySafe.getSingletonLazySafe();
		SingletonLazySafe singletonLazySafe2 = SingletonLazySafe.getSingletonLazySafe();
		System.out.println(singletonLazySafe1 == singletonLazySafe2);
		System.out.println(singletonLazySafe1);
		System.out.println(singletonLazySafe2);
	}
}

运行结果

我是安全滴懒汉式单例设计模式
true
com.cp.xiaobaibai.SingletonLazySafe@1b6d3586
com.cp.xiaobaibai.SingletonLazySafe@1b6d3586

  1. 静态内部类
package com.cp.xiaobaibai;

/**
 * 描述:单例模式——懒汉式——静态内部类
 * 创建人:cp小白白
 * 创建时间:2022/11/18 8:52
 */
public class SingletonStaticInner {
	
	private SingletonStaticInner() {
		System.out.println("我是静态内部类懒汉式单例设计模式");
	}

	private static class StaticInner {
		// 这涉及static final变量的命名。规范,不懂得可以去搜一下。
		private static final SingletonStaticInner SINGLETON_STATIC_INNER = new SingletonStaticInner();
	}

	public static final SingletonStaticInner getSingletonStaticInner() {
		return StaticInner.SINGLETON_STATIC_INNER;
	}
}

测试类

package com.cp.xiaobaibai;

/**
 * 描述: 单例模式测试类
 * 创建人:cp小白白
 * 创建时间:2022/11/17 17:17
 */
public class Singleton {
	public static void main(String[] args) {
		// 懒汉式不安全安全单例设计模式测试
		/* ...... */
		// 懒汉式安全单例设计模式测试
		/* ...... */
		// 懒汉式静态内部类单例设计模式测试
		SingletonStaticInner singletonStaticInner1 = SingletonStaticInner.getSingletonStaticInner();
		SingletonStaticInner singletonStaticInner2 = SingletonStaticInner.getSingletonStaticInner();
		System.out.println(singletonStaticInner1 == singletonStaticInner2);
		System.out.println(singletonStaticInner1);
		System.out.println(singletonStaticInner2);
	}
}

运行结果

我是静态内部类懒汉式单例设计模式
true
com.cp.xiaobaibai.SingletonStaticInner@1b6d3586
com.cp.xiaobaibai.SingletonStaticInner@1b6d3586

  1. 双重检查锁定
package com.cp.xiaobaibai;

/**
 * 描述:单例模式——懒汉式——双重检查锁定
 * 创建人:cp小白白
 * 创建时间:2022/11/18 9:00
 */
public class SingletonDoubleCheckLock {

    private SingletonDoubleCheckLock() {
        System.out.println("我是双重检查锁定懒汉式单例设计模式");
    }

    private volatile static SingletonDoubleCheckLock singletonDoubleCheckLock = null;

    public static SingletonDoubleCheckLock getSingletonDoubleCheckLock() {
        if (singletonDoubleCheckLock == null) {
            synchronized (SingletonDoubleCheckLock.class) {
                if (singletonDoubleCheckLock == null) {
                    singletonDoubleCheckLock = new SingletonDoubleCheckLock();
                }
            }
        }
        return singletonDoubleCheckLock;
    }
}

测试类

package com.cp.xiaobaibai;

/**
 * 描述: 单例模式测试类
 * 创建人:cp小白白
 * 创建时间:2022/11/17 17:17
 */
public class Singleton {
	public static void main(String[] args) {
		// 懒汉式不安全安全单例设计模式测试
		/* ...... */
		// 懒汉式安全单例设计模式测试
		/* ...... */
		// 懒汉式静态内部类单例设计模式测试
		/* ...... */
		// 懒汉式双重检查锁定单例设计模式测试
		SingletonDoubleCheckLock singletonDoubleCheckLock1 = SingletonDoubleCheckLock.getSingletonDoubleCheckLock();
		SingletonDoubleCheckLock singletonDoubleCheckLock2 = SingletonDoubleCheckLock.getSingletonDoubleCheckLock();
		System.out.println(singletonDoubleCheckLock1 == singletonDoubleCheckLock2);
		System.out.println(singletonDoubleCheckLock1);
		System.out.println(singletonDoubleCheckLock2);
	}
}

运行结果

我是双重检查锁定懒汉式单例设计模式
true
com.cp.xiaobaibai.SingletonDoubleCheckLock@1b6d3586
com.cp.xiaobaibai.SingletonDoubleCheckLock@1b6d3586

  1. 思考

(1)运行结果中为什么只输出类中的一次“我是…模式”,不是调用了两次吗?
(2)为什么我用的“==”而不用“.equals”?
(3)如果三次输出语句随机调换位置,输出语句会有什么变化?

(1)如果你对单例模式的定义很明白,那第一题你就很容易答出来。单例模式,重点在单例,有且只有一个实例。不管你调用几次,只要它实例化了,就会在堆中分配的内存空间中,只有程序终止后才会被释放。
(2)“==”和“.equals”的区别大家要是知道的话,这里应该很容易了解。还是那个重点,单例,有且只有一个实例。我要比较地址值是否一样,来确定它实例化了几次。
(3)无论输出怎么变化,唯一不变的就是类中的那句输出“我是...模式”,地址值和比较结果会随着输出语句变化二变化。

  1. 进阶

(1)既然说到线程不安全,为什么会线程不安全,来看一下例子。

package com.cp.xiaobaibai;

/**
 * 描述: 单例模式进阶测试类
 * 创建人:cp小白白
 * 创建时间:2022/11/18 10:28
 */
public class SingletonSenior {
	public static void main(String[] args) {
		// 多线程下检验懒汉式不安全单例设计模式
		for (int i = 0; i < 5; i++) {
			new Thread(() -> {
				System.out.println(SingletonLazyUnsafe.getSingletonLazyUnsafe());
			}).start();
		}
	}
}

输出结果

我是不安全滴懒汉式单例设计模式
我是不安全滴懒汉式单例设计模式
我是不安全滴懒汉式单例设计模式
我是不安全滴懒汉式单例设计模式
我是不安全滴懒汉式单例设计模式
com.cp.xiaobaibai.SingletonLazyUnsafe@46a00ba1
com.cp.xiaobaibai.SingletonLazyUnsafe@72bb9f6e
com.cp.xiaobaibai.SingletonLazyUnsafe@39ae8a9b
com.cp.xiaobaibai.SingletonLazyUnsafe@d166de5
com.cp.xiaobaibai.SingletonLazyUnsafe@1acc1ca0

可以很明显的看出,类被实例化了好几次。违背了有且只有一个的实例的原则。所以在多线程的环境下是不安全的。也可以增大次数,看看效果。

(2)怎么解决线程不安全问题呢,加锁呗。双重检查锁定机制不就来了吗,但是,双重检查锁定机制是不是锁太重了,每次访问过来时候都需要同步,太过于影响性能了,消耗了太多的资源。有的帖子说它高并发安全,高效,个人还是不太推荐使用,锁太重了。
(3)静态内部类的衍生就来了,既能解决了多线程安全问题,还能解决同步带来的性能影响。

2.2、饿汉式

在类加载时,就立即实例化,并且创建单例对象。
因为其在线程还没出现前就已经实例化了,所以它是线程安全滴。

吐槽:目前还没理解它为什么叫饿汉式,这个饿的定义是对谁定义的。

工作中。。。周末有时间再写。。。公司电脑被设置权限了,不能复制了,暴风哭泣

2.3、登记式

通过一个类专门的类对各单例模式的单一实例进行管理和维护。

吐槽:这个登记式吧,我没有找到特别好的定义。我也是第一次了解这个,可能以前也看到过,但是印象不深。有大佬知道的,欢迎私信或者评论,被太学术了,大白话一点好。

工作中。。。周末有时间再写。。。公司电脑被设置权限了,不能复制了,暴风哭泣

3、总结

单例模式是Java设计模式中比较简单的一种,既然存在就有存在的意义。培训机构也会对它进行一些讲解,可见它也是很重要的。
设计模式吗,设计,往往就是一种思维惯性。思维思维,人也有主观和客观之分,代码也是人写的,不是吗。

4、建议

我的文章看看就好,别深究,要有自己的理解,每个人都有自己的理解,无论对错,不要把别人的理解当成你的理解,别人的理解可以作为参考,但一定要对知识有自己的看法。
要多写代码,看理论知识点,永远是看。一看都会,一写全不会,没事多写写,熟悉熟悉它。

人非圣贤,孰能无惑!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值