一、定义
设计模式:一种设计思想,针对不同的业务场景,用不同的方式去设计代码结构,其最最本质的目的是为了解耦,延伸一点的话,还有为了可扩展性和健壮性,但是这都是建立在解耦的基础之上。
单例模式:是一种常用的软件设计模式,单例对象的类必须保证只有一个实例存在。保证一个类仅有一个实例,并提供一个访问他的全局访问点,该实例被所有程序模块共享。
二、单例模式构造
public class Singleton {
private Singleton() {} //关键点0:构造函数是私有的
private static Singleton single = null; //关键点1:声明单例对象是静态的
private static object obj= new object();
public static Singleton GetInstance() //通过静态方法来构造对象
{
if (single == null) //关键点2:判断单例对象是否已经被构造
{
lock(obj) //关键点3:加线程锁
{
if(single == null) //关键点4:二次判断单例是否已经被构造
{
single = new Singleton();
}
}
}
return single;
}
}
关键点0/1:私有的构造函数保证该类不能在外面定义类的对象,单例类不能被实例化,单例实例只能静态调用
关键点2/4:检测两次单例是否被构造,原因是,有可能延迟加载或者缓存原因,造成构造多个实例,违反了单例的初衷。
关键点3: 保证线程安全,锁住的必须是个引用类型,如果锁是值类型(如int),每个不同的线程在声明的时候值类型变量的地址都不一样,那么上个线程锁住的东西下个线程进来会认为根本没锁,相当于每次都锁了不同的门。而引用类型的变量地址是相同的,每个线程进来判断是否被锁的时候都是判断同一个地址,相当于是锁在同一扇门,起到了锁的作用。
三、单例模式优缺点:
优点:
1.在单例模式中,活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例。这样就防止其它对象对自己的实例化,确保所有的对象都访问一个实例 。
2.单例模式具有一定的伸缩性,类自己来控制实例化进程,类就在改变实例化进程上有相应的伸缩性。
3.提供了对唯一实例的受控访问。4.由于在系统内存中只存在一个对象,因此可以 节约系统资源,当 需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能。
5.允许可变数目的实例。
6.避免对共享资源的多重占用。
缺点:
1.不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
2.由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。
3.单例类的职责过重,在一定程度上违背了“单一职责原则”。
4.滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。
四、两种模式:
1、饿汉式:预先加载,单例实例在类装载时就构建。
public class Test {
private Test() {
}
public static Test instance = new Test();
public Test getInstance() {
return instance;
}
}
优点:①线程安全 ②在类加载的同时已经创建好一个静态对象,调用时反应速度快
缺点:资源效率不高,可能getInstance()永远不会执行到,但执行该类的其他静态方法或者加载了该类
2、懒汉式:单例实例在第一次被使用时构建,延迟初始化。
class Test {
private Test() {
}
public static Test instance = null;
public static Test getInstance() {
if (instance == null) { //多个线程判断instance都为null时,在执行new操作时多线程会出现重复情况
instance = new Singleton2();
}
return instance;
}
}
优点: 避免了饿汉式的那种在没有用到的情况下创建事例,资源利用率高,不执行getInstance()就不会被实例,可以执行该类的其他静态方法。
缺点:懒汉式在单个线程中没有问题,但多个线程同时访问的时候就可能同时创建多个实例,而且这多个实例不是同一个对象,虽然后面创建的实例会覆盖先创建的实例,但是还是会存在拿到不同对象的情况。解决这个问题的办法就是加锁synchonized,第一次加载时不够快,多线程使用不必要的同步开销大。
3、双重检验:懒汉式+同步锁+检验
class Test {
private Test() {
}
public static Test instance = null;
public static Test getInstance() {
if (instance == null) { //第一次检验
synchronized (Test.class) { //锁
if (instance == null) { //第二次检验
instance = new Test(); //实例化
}
}
}
return instance;
}
}
优点: 资源利用率高,不执行getInstance()就不被实例,可以执行该类其他静态方法 缺点: 第一次加载时反应不快,由于java内存模型一些原因偶尔失败
4、静态内部类:
class Test {
private Test() {
}
private static class SingletonHelp {
static Test instance = new Test();
}
public static Test getInstance() {
return SingletonHelp.instance;
}
}
优点: 资源利用率高,不执行getInstance()不被实例,可以执行该类其他静态方法 缺点: 第一次加载时反应不够快
一般采用饿汉式,若对资源十分在意可以采用静态内部类,不建议采用懒汉式及双重检测
来源: