单例模式也叫做单肩模式,也是一种创建型模式,是我们日常开发中最常使用的一种设计模式,经常被用来封装一些工具类,例如数据库连接等。
单例模式的定义:
单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例。即一个类只有一个对象实例
单例模式分为以下几种:
①饿汉单例模式
②懒汉单例模式
③IoDH单例模式
④枚举单例模式
下面我们一一的进行介绍:
1.首先是饿汉单例模式,顾名思义“饿汉”,代表急着“吃饭”(这里的饭应该是指的实例对象),所以很早就创建出来。不多说,上代码:
package singleton; public class HungrySingletonP { private static HungrySingletonP instance=new HungrySingletonP(); public HungrySingletonP(){} public static HungrySingletonP getInstance(){ return instance; } }
这段代码很形象的体现了饿汉模式。
这种方法在类加载的时候就已经实例化了(只创建唯一的实例),所以不存在线程上的一些问题。但是,也因为如此如果有太多的单例,且这些实例不经常使用那么久会造成对内存的浪费。
2.懒汉模式,同样什么叫做懒汉模式?一个懒惰的人,只有去吃饭的时候才会去刷碗(昨天用过的脏碗),即:只有当用到对象的时候才去创建对象,来上代码:
package singleton; public class LasySingletonV1 { private static LasySingletonV1 instance; public LasySingletonV1(){} public static LasySingletonV1 getInstance(){ if(instance==null){ return new LasySingletonV1(); }else return instance; } }
上面的这段代码是懒汉模式,当我们不需要实例的时候,它不会创建实例,只有需要实例的时候,才会创建,节省空间。
但是,我们不推荐使用,因为我们原来的设计理念是:当需要的时候(并且instance为空)创建实例,当已经创建过后,如果还需要实例,则判断instance是否为空,因为前边已经创建过了,不为空,所以直接返回之前已经创建的实例。
以上的想法是很好的,但是它是线程不安全的。因为:当有多个线程同时调用这个方法时,因为同时判断实例为空,所以会创建很多个实例,这不符合单例模式的设计理念(一个类只有一个实例对象)。
所以我们需要对它进行改进,因为它会异步创建多个实例,多以我们很容易就能想到,在getInstance方法之前加上synchronized进行同步:
package singleton; public class LasySingletonV2 { private static LasySingletonV2 instance; public LasySingletonV2(){} public synchronized LasySingletonV2 getInstance(){ if(instance==null){ return new LasySingletonV2(); }else return instance; } }
上面这样,就不会创建多个实例对象符合单例模式的概念。
但是上面这样的设计使得我们每次需要目标实例的时候都要排队等待,假设有很多线程都在调用这个getInstance方法,那么就会陷入很长时间的等待,大大降低的程序的效率。
所以我们还要对程序进行一定的修改,如果我们创建一个
package singleton; public class LasySingletonV3 { private static LasySingletonV1 instance; public LasySingletonV3(){} public LasySingletonV3 getInstance(){ if(instance==null){ synchronized(LasySingletonV3.class){ if(instance==null){ return new LasySingletonV3(); } } } return instance; } }
以上的方法是懒汉模式的完整版本,我们来仔细分析一下:
当有多个线程第一次调用这个方法的时候,都满足instance为空,来到下一步,先获得锁的线程进入下一步继续判断是否为空,为空,然后创建实例返回实例。
没有获得锁的线程一直等待到获得锁的线程释放锁,当在等待的线程获得锁的时候进入下一步,还要进行判断instance是否为空,但是这个时候instance已经不为空了,因为前面的线程已经创建了实例,所以返回已经创建好的实例。
以上是第一批调用getInstance方法的线程,当后续的线程调用这个方法的时候就不用进行锁的获取了和释放了,因为第一步已经判断instance不为空,直接返回instance实例。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持亿速云。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。