🍁 作者:知识浅谈,CSDN签约讲师,CSDN博客专家,华为云云享专家,阿里云专家博主
📌 擅长领域:全栈工程师、爬虫、ACM算法
💒 公众号:知识浅谈
🔥 联系方式vx:zsqtcc
🤞大佬,人人都说精通的单例模式,你精通了吗🤞
正菜来了⛳⛳⛳
概括起来,要实现一个单例,需要关注的点有下面几个:
- 构造函数需要是private访问权限的,这样才能避免外部通过new创建实例;
- 考虑对象创建时的线程安全问题;
- 考虑是否支持延迟加载:
- 考虑getlnstance0性能是否高(是否加锁)
🎈饿汉式
类加载时直接实例化单例对象
饿汉式的实现方式比较简单。在类加载的时候,instance静态实例就已经创建并初始化好了,所以,instance实例的创建过程是线程安全的。不过,这样的实现方式不支持延迟加载(在真正用到IdGenerator的时候,再创建实例),从名字中我们也可以看出这一点。
具体的代码实现如下所示:
public class Main { //在类加载的时候就已经实例化好了,不好的地方就是如果用不到就相当于无效占用空间了,但是不会出现多线程的问题 private static Main test = new Main(); private Main(){} public Main getInstance(){ return test; } public static void main(String[] args) { System.out.println(Main.test); } }
🎈懒汉式
🍮双重检查模式
之所以双重检查,为了保证多线程创建多个对象形成覆盖的问题。
为什么使用volatile,是因为只有加了volatile,才能保证可见性,在不同的线程中对象的变量值都是可见的。
public class Main { private static volatile Main test; private Main(){} public static Main getInstance(){ if(test==null){ synchronized (Main.class){ if(test==null) test = new Main(); } } return test; } public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newFixedThreadPool(5); CountDownLatch count = new CountDownLatch(5); for (int i = 0; i < 5; i++) { executorService.execute(new Runnable() { @Override public void run() { System.out.println(Main.getInstance()); count.countDown(); } }); } count.await(); executorService.shutdown(); } }
🍮静态内部类模式
主要用到的原理是 首先静态内部类只有在调用的时候,第一次进行初始化,也就是单例对象只在第一次调用的时候创建。
public class Main { private Main(){} static class A{ private static Main test = new Main(); } public static Main getInstance(){ return A.test; } public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newFixedThreadPool(5); CountDownLatch count = new CountDownLatch(5); for (int i = 0; i < 5; i++) { executorService.execute(new Runnable() { @Override public void run() { System.out.println(Main.getInstance()); count.countDown(); } }); } count.await(); executorService.shutdown(); } }
🍚总结
以上就是个人对23种设计模式种的单例模式浅谈,希望有所帮助。