当前位置: 首页> 游戏> 手游 > 互联网营销师培训课程免费_网页设计与制作txt_百度竞价项目_小程序推广

互联网营销师培训课程免费_网页设计与制作txt_百度竞价项目_小程序推广

时间:2025/7/14 1:09:22来源:https://blog.csdn.net/gdxdekx/article/details/145516049 浏览次数:0次
互联网营销师培训课程免费_网页设计与制作txt_百度竞价项目_小程序推广

一、定义

单例模式算是比较简单的一种设计模式了,其核心思想就是确保一个类只有一个实例,并提供一个全局访问点。

具体点来说,就是我们把单例类设计成自己管理的一个单独实例,同时避免其他类创建单例实例,要想获取单例实例,通过单例类是唯一的方式。所谓的全局访问点,单例实例提供给其他类的获取实例的方法,也就是在这个方法中,保证了单例类只有一个实例。

二、使用场景

有一些对象其实我们只需要一个,比如:线程池、缓存、日志对象等等,这些对象只能有一个实例,如果有多个,会导致很多问题,比如程序异常、资源使用过量等。

三、实现

单例模式实现的核心就是将构造器私有化,这样一来只有单例自身才能创建对象。

线程不安全的实现

public class SimpleSingleton {//单例实例private static SimpleSingleton instance;//获取单例实例,如果不存在就创建public static SimpleSingleton getInstance(){if(instance == null){instance = new SimpleSingleton();}return instance;}private SimpleSingleton(){System.out.println(Thread.currentThread().getId() + "," + System.currentTimeMillis() + ",创建了SimpleSingleton");}
}

这样实现起来也很简单,在一般情况下是没有问题的,但是在多线程的情况下,就会出现问题。

public class SingletonTest {public static void main(String[] args) {testSimpleSingletonTask();}static void testSimpleSingletonTask(){ExecutorService pool = Executors.newFixedThreadPool(10);SimpleSingletonTask simpleSingletonTask = new SimpleSingletonTask();pool.execute(simpleSingletonTask);pool.execute(simpleSingletonTask);pool.execute(simpleSingletonTask);pool.execute(simpleSingletonTask);pool.execute(simpleSingletonTask);pool.execute(simpleSingletonTask);pool.shutdown();}static class SimpleSingletonTask implements Runnable{@Overridepublic void run() {System.out.println(Thread.currentThread().getId() + "," + SimpleSingleton.getInstance());}}
}

输出结果:
在这里插入图片描述

可以看到,在多线程的情况下,每个线程都创建了一个单例实例,这肯定不是我们想要的结果,那为什么会这样呢?

其实如果对多线程编程有了解的话很容易看出来,单例类中的instance是一个共享变量,而getInstance中提供了对这个共享变量的修改,但修改是线程不安全的,很容易在多个线程执行这个方法的时候,都判断变量为空,然后都创建了一个实例赋值。

线程安全的单例模式

上述线程不安全的原因就是对共享变量instance修改时没有考虑多线程的情况,那最简单的解决方法就是直接给getInstancesynchronized,改为下面这样:

public class Singleton {//共享变量加上volatileprivate volatile static Singleton instance;private Singleton(){System.out.println(Thread.currentThread().getId() + "," + System.currentTimeMillis() + ",创建了Singleton");}//直接加synchronizedpublic static synchronized Singleton getInstance(){if(instance == null){instance = new Singleton();}return instance;}}

这样肯定可以解决问题,但实际上,我们只有在第一次创建实例的时候需要加同步锁,在之后的时间里,实例已经存在了,就没有必要加锁了,这样会影响效率。

所以就有了下面这样的解决方法,双重校验锁:

public class Singleton {private volatile static Singleton instance;private Singleton(){System.out.println(Thread.currentThread().getId() + "," + System.currentTimeMillis() + ",创建了Singleton");}public static Singleton getInstance(){if(instance == null){//如果为空了,再去加锁创建实例synchronized(Singleton.class){//获取之后再判断一下,双重校验。原因是因为多线程的情况下,一个线程获取到了锁进来执行,其他的线程等待获取锁,释放锁后,其他的线程会陆续获取锁再次进来,所以获取锁之后还需要再判断一下是否已经创建了if(instance == null){instance = new Singleton();}}}return instance;}}

我们用下面的代码测试:

public class SingletonTest {public static void main(String[] args) {testSafeSingletonTask();}static void testSafeSingletonTask(){ExecutorService pool = Executors.newFixedThreadPool(10);SafeSingletonTask safeSingletonTask = new SafeSingletonTask();pool.execute(safeSingletonTask);pool.execute(safeSingletonTask);pool.execute(safeSingletonTask);pool.execute(safeSingletonTask);pool.execute(safeSingletonTask);pool.execute(safeSingletonTask);pool.shutdown();}static class SafeSingletonTask implements Runnable{@Overridepublic void run() {System.out.println(Thread.currentThread().getId() + "," + Singleton.getInstance());}}}

结果,只有一个线程创建了实例,其他线程获取到的都是这个实例

在这里插入图片描述

关键字:互联网营销师培训课程免费_网页设计与制作txt_百度竞价项目_小程序推广

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: