今天我们就来讲讲单列模式
何为单列模式:
(1):单列类只有一个实例
(2):共享资源,全局使用
(3):节省创建时间,提高性能
说白了就是保证单个jvm中只有一个实列
不过任何东西都是一把双刃剑,有优秀的地方,就有不足的地方:
单列可能存在线程不安全的问题。(这个后续在考虑)
来:我们用代码演示一下单列模式
public class Singlenton {
//定义一个私有的静态对象
private static Singlenton singlenton = new Singlenton();
//定义私有构造方法
private Singlenton(){}
/**
* 定有公共方法返回该对象的实列
*
*
*/
public static Singlenton getInstance(){
return singlenton;
}
}
我们来总结一下饿汉式的优缺点:
优点:先天性线程安全,为什么先天性了,因为当类加载的时候,就被创建该对象。
缺点:如果项目使用过多的饿汉式会产生问题
(1)项目在启动的时候会变的非常慢,存放在方法区占用内存比较大
(2)如果用户不使用该对象的时候,也会被提前创建好,造成内存的浪费。
/*
单列模式之懒汉式
*/
public class Singlenton {
private static Singlenton singlenton;
//定义私有构造
private Singlenton(){}
public static Singlenton getSinglenton(){
//当第一次singlenton等于null时,才会被初始化
if(singlenton == null){
singlenton = new Singlenton();
}
//不等于null,直接返回
return singlenton;
}
}
我们来总结一下懒汉式的优缺点:
优点:当真正需要使用该对象的时候才会被加载,被初始化,提高了性能
缺点:线程安全问题,在多线程情况下,可能会被初始化多次
哎呀,这个线程安全问题还是挺严重的,有问题不是目的,目的是怎么解决它,这才是问题,废话不多说
第一种方案,在会出现线程安全问题的代码前加上synchronized关键字,
那么,这样问题又来了,虽然线程安全的问题是解决了,但是程序执行效率明显下降了
我们必须从源头抓起,比如为什么会产生线程安全问题:当多个线程共享同一个数据,做“写”的操作的时候可能会出现线程安全问题,读是不存在线程安全问题的。
那么我们想想,懒汉式解决线程安全问题为什么效率比较低了,确实因为同步,读和写都加上了锁。
如图所示:当第一次singlenton等于null时,才会被初始化,创建对象,而第一次创建对象的时候才会加锁,之后获取该对象的时候不需要加锁。
那么明白了这些之后,我们就来使用最优的解决方案:双重检验锁 解决懒汉式读和写都加上锁的问题
读的时候不加锁,写的时候才会加锁。
public class Singlenton {
private static Singlenton singlenton;
//定义私有构造
private Singlenton(){}
public static Singlenton getSinglenton(){
//当第一次singlenton等于null时,才会被初始化,才能去创建对象才会加锁,保证线程安全问题
if(singlenton == null){
synchronized (Singlenton.class){
//当前线程已经获取到锁,在判断一下该对象是否已经初始化过,没有初始化的,进行创建
if(singlenton == null){
singlenton = new Singlenton();
}
}
}
//不等于null,直接返回
return singlenton;
}
}
但是我觉得还是不够好,毕竟加了锁,如何解决读和写都不加锁,还能保证唯一性。
当然有,静态内部类形式
代码演示一遍:
/*
单列模式之静态内部类
*/
public class Singlenton {
public static Singlenton getInstance(){
return SinglentonUtils.singlenton;
}
//在类里面嵌套的静态类
private static class SinglentonUtils{
private static final Singlenton singlenton = new Singlenton();
}
}
这种单列模式是最简单的,首先静态内部类特征:继承懒汉式优点,同时了也解决了双重检验锁第一次加载慢的问题,读和写都不需要同步,效率非常高。