前言 设计模式代表了前人的最佳实践,在水平达到了一定的层级之后,总是要接触设计模式的。本文旨在使用通俗易懂的例子,帮助初学者理解单例模式。 单例模式顾名思义,一个类仅能有一个实例。所以他的对象不能被手动实例化(就无法保证只有一个实例),而是由该类创建,并提供访问实例对象的方法。 从前有一群笨笨的小猪🐖,总共100头吧。 小猪的饮食很规律,吃饭前,如果桌子上没有蛋糕,第一头小猪申请100个小蛋糕放到桌子上,然后自己拿一个。如果桌子上有蛋糕,其他小猪只需要拿蛋糕就可以了,不需要再次申请。
Day1饲养员上班第一天,做蛋糕比较懒(懒汉模式),小猪申请完之后,需要等一会,才会把蛋糕放到桌子上。 好多小猪同时到达饲养员身边,同时申请100个蛋糕,最后饲养员拿出了上千个蛋糕,猪圈公司损失惨重,饲养员被扣工资。 Day2 Day3 Day4 我们从小猪抢蛋糕的故事来理解单例模式,饲养员做蛋糕的方式(懒惰或者勤快)对应我们两种方法(懒汉模式和饿汉模式)。 懒汉模式:(需要创建类我才创建,不需要创建我就不创建) 饿汉模式: (不管你需不需要,我都先创建一个实例对象) 在这里,线程就是我们的小猪,同时争抢的情况就是多线程冲突,不难发现饿汉模式对应饲养员第四天的情况,在饿汉模式下,对象实例已经被提前创建,牺牲了内存空间,但是解决了线程安全的问题,是线程安全的实现。 现在我们看一下懒汉模式,不难发现懒汉模式对应饲养员第一天的情况,在多线程情况下,多个线程同时申请创建实例,这样就创建了多个对象实例,不符合我们的单例设计模式。 第一个线程产生了一个cake引用对象,但此时还没有创建实例对象(没有调用new Cake()方法),然后后面的线程都突破了判断语句的屏障,都来实例化对象,对应于小猪同时申请蛋糕。 有人可能说为什么不先调用new Cake()方法,这里设计到一个指令重排的问题,感兴趣的朋友查看相关资料。 那怎么解决线程不安全的问题呢?参考饲养员第二天的做法,可以使用synchronized关键字。 我们在拿蛋糕的时候进行排队处理,(对获取实例方法进行加锁) 我们也说了,这种方式虽然能保证线程安全,但是效率不是很高。 对于提高效率的方法,我们参考饲养员第三天的做法,只对申请蛋糕(创建实例)进行排队(加锁),对于拿蛋糕不做限制,(细化锁的粒度,只对创建实例的步骤加锁) 但是现在这样真的可以线程安全了吗? 我们可以看到在对象被实例化之前,可能有多个线程突破了判断语句的屏障,我们现在加的同步锁只能保证这几个线程是依次创建实例对象,并不能保证单例。 (我们继续参考饲养员第四天的做法——-第一个小猪申请完,此时桌子上并没有蛋糕(饲养员太懒了),其他小猪还会继续申请,这时候饲养员会告诉剩下的小猪蛋糕正在做,不用继续申请了。) 我们需要告诉其他小猪,蛋糕正在做,怎么告诉呢? 这里我们可以在锁内部(蛋糕放到桌子之前),再加一个判断(告诉其他小猪不必申请),代码如下: 我们可以看到现在有了两个判断语句和一个同步锁,我们一般称为 值得注意的是我们的coke对象前加了volatile关键字修饰,该关键字能够防止指令重排以及保证内内存可见性,加上他后可以更加保证线程安全,感兴趣的朋友查看相关资料。 希望大家看完此文能够对单例模式有一个比较清晰的认识,码字不易,尊重原创,转载请加入本文链接—查看原文。
文章目录
正文—-什么是单例模式?
———-有趣的小猪抢蛋糕
———-单例模式
前言
什么是单例模式?
有趣的小猪抢蛋糕
第二天,饲养员多了一个心眼,小猪先排队(加锁)。等第一个小猪申请完,并且等他把蛋糕放到桌子上,然后小猪依次排队一个个拿。这次蛋糕没有损失,但是效率很低。
第三天,饲养员发现效率还可以提高,一旦蛋糕放到了桌子上,小猪们就没必要排队,直接一人拿一个就可以了。但是在桌子上没有蛋糕时,还是要控制一下,第一个小猪申请完,此时桌子上并没有蛋糕(饲养员太懒了),其他小猪还会继续申请,这时候饲养员会告诉剩下的小猪蛋糕正在做,不用继续申请了。等到桌子上有了蛋糕,就不用告诉他们了。效率很高。
第四天,饲养员发现自己还是太懒了,变得勤快了(饿汉模式),他提前把蛋糕做好,然后提前放在桌子上,这样也就没有了小猪同时申请几千个蛋糕以及排队等待的情况了。
单例模式
public class Cake{ private static Cake cake; //蛋糕实例 private Cake(){}; //构造方法 public static Cake getHundredCake() { //获取100个蛋糕 if (cake == null) { //如果桌子上没有蛋糕 cake = new Cake(); } return cake; } }
public class Cake{ private static Cake cake = new Cake(); //提前创建蛋糕实例 private Cake(){}; //构造方法 public static Cake getHundredCake() { //获取100个蛋糕 return cake; } }
比如下面的代码if (cake == null) { //如果桌子上没有蛋糕 cake = new Cake(); } )
public class Cake{ private static Cake cake; //蛋糕实例 private Cake(){}; //构造方法 public static synchronized Cake getHundredCake() { //获取100个蛋糕,加上synchronized关键字,保证同步 if (cake == null) { //如果桌子上没有蛋糕 cake = new Cake(); } return cake; } }
public class Cake{ private static Cake cake; //蛋糕实例 private Cake(){}; //构造方法 public static Cake getHundredCake() { //获取100个蛋糕 if (cake == null) { //如果桌子上没有蛋糕 synchronized (Singleton.class) { //排队申请蛋糕 cake = new Cake(); } } return cake; } }
public class Cake{ private volatile static Cake cake; //蛋糕实例 private Cake(){}; //构造方法 public static Cake getHundredCake() { //获取100个蛋糕 if (cake == null) { //如果桌子上没有蛋糕 synchronized (Singleton.class) { //排队申请蛋糕 if (cake == null) { //如果正在做,但是还没放到桌子上 cake = new Cake(); } } return cake; } }
双重检查锁double-checked locking
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算