第八篇:单例模式

来源:互联网 发布:百马百担c语言编程答案 编辑:程序博客网 时间:2024/06/05 10:33

关于单例模式我并不想做过多解释,网络上有一大堆关于它的定义,简而言之,单例就是指单个对象,整个程序的运行生命周期内某个对象只会生成一次!

这么做有什么意义呢?很简单,你的电脑开机,有多个回收站对象会有什么后果?你删掉一个文件它该被放入哪个回收站? 有多个注册表会怎样? 程序中有多个数据库连接池会怎样? 这些问题留给你去思考吧!

正因为某些对象的特殊性,整个程序生命周期内只能出现一个它的实例, 又或者,某些对象的创建非常复杂非常消耗资源,且它是不会随着程序的运行而有所改变的,那么我们也期望只生产一次这个对象,后面直接拿来复用! 那么这种只会生成一次某个对象的编码技巧,我们就将其称为单列模式!

网络上好像说是有6中实现单例的方法,但我个人认为只有4种!另外2种是网友的代码演变,压根算不上... 当然,最有效好用的只有一种,我稍后将代码贴出来!

OK,让我们拿出点干货来,让代码来说话吧!


第一种:饿汉式(所谓饿汉就是指不管有没有人要使用我,我先把自己给创建出来)

public class Singleton {/**饿汉式,直接创建对象*/private static final Singleton singleton = new Singleton();/**构造器私有化,这样别人就无法创建我!*/private Singleton() {}/**必须提供一个让客户端获取自身实例的方法*/public static Singleton getInstance(){return singleton;}public static void main(String[] args) {Singleton s1 = Singleton.getInstance();Singleton s2 = Singleton.getInstance();System.out.println(s1==s2); //===>>>输出:true}}

如上面代码所示,我们的Singleton类的实例只可能有一个,不用担心线程问题,因为它是随着类加载而实例化的,而类只会被加载一次(当然,也可以被加载多次,关于这点我打算后面再写篇让同一个类加载多次的文章,这里略过) ; 虽然它是安全的,但也有一个问题,假设这个类的创建非常复杂非常消耗资源,但是由于是饿汉式,不管有没有真正要使用这个类的实例,它总是会创建一次自己,从而占用我们的系统资源,假如压根没有人用到它,那就会造成资源浪费,由此,下面的懒汉式诞生了!


第二种:懒汉式(所谓懒汉式是指等到有人要使用我时,我就开始创建一次自己)

public class Singleton {/**懒汉式,等到有人使用时再创建!*/private static Singleton singleton ;/**构造器私有化,这样别人就无法创建我!*/private Singleton() {}/**必须提供一个让客户端获取自身实例的方法*/public static Singleton getInstance(){//判断是否为空,如果是第一次被人使用,则必定是空if( singleton==null ){singleton = new Singleton();}return singleton;}public static void main(String[] args) {Singleton s1 = Singleton.getInstance();Singleton s2 = Singleton.getInstance();System.out.println(s1==s2); //===>>>输出:true}}
如上面代码所示,我们的Singleton现在不再随着类的加载而实例化了,它只有等到真正有人用到它时才会去实例化一次,这归功于那句if...else...的功能,但也正是由于if...else...这里的代码所在,它被引入了线程不安全的隐患,在多个线程同时调度下,假如A,B两个线程都进入到了getInstance()中,此时singleton为空,那么就会被创建2次,这是我们无法容忍的,于是,有了下面的双重加锁的代码实现!


第三种:懒汉式变种(双重检查加锁)

public class Singleton {/**懒汉式,等到有人使用时再创建!*/private static Singleton singleton ;/**构造器私有化,这样别人就无法创建我!*/private Singleton() {}/**必须提供一个让客户端获取自身实例的方法*/public static Singleton getInstance(){if( singleton==null ){//加一把锁,且再进行一次判断synchronized (Singleton.class) {//当A线程执行到这里,if条件成立,singleton将被实例化,//A线程执行完synchronized代码块,释放锁//而后B线程允许放行进入到这里,此时if条件将不再成立!if( singleton==null ){singleton = new Singleton();}}}return singleton;}}
如果我们直接在getInstance()方法上加锁(有人将这种做法也称之为一种实现方式...所以有人说有6种实现方式),那么并发上来,将会造成多个线程同时等待,而将其放入if条件之中,将会大量减少线程等待(因为由于上一个线程的执行完毕,if条件将不再成立),同时也保证了多线程下该对象实例只会被创建一次! 但无论如何,都会造成线程等待,那么有没有一种更好的方式来实现单例呢?既可以不造成线程等待,同时又是安全的,保证只会创建一次对象,同时又是基于懒汉式的创建方式, Ok,终极方法,内部类实现!


第四种:懒汉式变种(内部类实现单例,我认为是最好的一种)

public class Singleton {/**构造器私有化,这样别人就无法创建我!*/private Singleton() {}//使用内部类!private static class Inner{private static final Singleton singleton = new Singleton();}/**必须提供一个让客户端获取自身实例的方法*/public static Singleton getInstance(){return Inner.singleton;}public static void main(String[] args) {Singleton s1 = Singleton.getInstance();Singleton s2 = Singleton.getInstance();System.out.println(s1==s2); //===>>>输出true}}
OK,我们来研究一下上面的代码吧!我们的Inner是一个静态内部类,就算有一亿个线程,它也只会被类加载器装载一次,而里面的singleton会随着Inner的类装载而被实例化,所以,它绝对是唯一不重复的,这一点,它和饿汉式的效果是一样的。但和饿汉式不同的时,Inner类只有当我们调用Singleton类的getInstance方法时才会被类加载器加载,所以,singleton的实例也只会在这个时候被创建,所以它不会造成资源浪费!如果理解不了,给我留言吧,文字我只能说到这啦!


Ok,喝杯咖啡润润喉...拜拜...


1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 一年不来月经了怎么办 我身上不来月经怎么办 取环没有取出来怎么办 脸水肿怎么办消得快 鼻子水肿怎么办消得快 勃起后软的快怎么办 手术后纱布掉了怎么办 中国单身的老了怎么办 双眼杯盘比增大,怎么办 出完精子腰疼怎么办 备孕2年没怀孕怎么办 发现怀孕了不想要怎么办 造影后通而不畅怎么办 脑梗病人晚上闹怎么办 两眼视力差距400怎么办 脑血清颗粒吃多怎么办 脸过敏吃了海鲜怎么办 如果qq密码忘了怎么办 qq密码被盗了该怎么办 qq号被别人盗了怎么办 qq不想让别人用怎么办 买了金科的房子怎么办 蟹爪莲叶子耷拉怎么办 金钻的叶子发黄怎么办 金钻叶子发焦黄怎么办 红钻叶子黄了怎么办啊 绿钻叶子黄斑点怎么办 金钻的叶子卷怎么办 金钻叶子有黑斑怎么办 怀孕60天没有胎心胎芽怎么办 单位不给交社保怎么办 公司没给足产假怎么办 小公司不给产假怎么办 机关不给陪产假怎么办 刚人流后又怀孕怎么办 怀孕50天不想要怎么办 生了孩子不想要怎么办 刚怀孕不想要孩子怎么办 怀孕一周不想要孩子怎么办 怀孕了不想要孩子怎么办 怀上二胎后悔了怎么办