Java学习笔记(3)-23种设计模式之单例模式
2020-02-20 本文已影响0人
非典型程序猿
每次看到招聘要求上大家都会写要熟悉设计模式,既然大家都在强调,那么也可想而知设计模式的重要性了,设计模式能够扩宽你写代码的思路,能够让你写出高水平的代码。那么笔者就这23种设计模式给大家一一做总结。
定义
单例,即指只有一个实例,对于我们日常的开发过程中,有的对象是需要大量反复使用的,如果每次都去创建新对象那么就会造成内存资源的浪费,因此我们在开发过程中就需要了解单例模式,我们就可以反复的使用同一个实例去做我们的操作,以达到节省内存,提高性能的目的。
特点
- 单例只有一个实例
- 单例必须由单例类自己创建
- 单例类为外部提供一个全局访问点
单例模式的使用
一般单例模式仅仅只为外部提供一个获取单例的方法,而创建单例的过程需要在这个单例类内部进行。总体来说使用过程是非常方便的。
单例模式的写法
懒汉式单例
public class User {
private static volatile User mUser=null; //保证 mUser 在所有线程中同步
private User(){} //private 避免类在外部被实例化
public static synchronized User getInstance()
{
//getInstance 方法前加同步
if(mUser==null){
mUser=new User();
}
return mUser;
}
}
首先我们分析懒汉式单例的特点,为什么叫懒汉式单例,是因为mUser在使用之前并没有被实例化,是在调用getInstance的时候才开始实例化,也就是使用时才加载,在这段代码中需要注意几个点。
- 为什么修饰mUser和getInstance是static关键字?
首先我们要知道static关键字所修饰的静态方法或变量,是不需要在对象实例化以后才可以使用的,单例的定义中明确讲了只给外界提供一个访问单例的入口,因此需要将getInstance修饰为static,而静态方法中只能使用静态变量,所以mUser也使用static修饰。 - 为什么修饰mUser需要使用volatile关键字?
首先我们要了解volatile关键字的作用,在java的多线程编程中,有ThreadLocal机制,在这里我们简单描述,也就是每一个线程对应都有自己临时拷贝并访问的一份内存数据,因此假设有线程A和线程B同时都对主内存里的一份数据a=0进行操作,开始时大家都知道a=0,但是在A,B运行的过程中,假设线程A将a的值更改为1了,但是由于ThreadLocal的机制,线程B仍然认为a=0,那么这时候就出现了a在线程A中和线程B中的值不一致了,也就是线程不安全了,因此volatile的作用就是强行让线程A,B去主内存中读取最新值,以达到线程安全的目的。 - 为什么要将构造方法私有化?
这也是从单例模式的特点中可以看出来,单例模式仅仅只为外界提供一个访问单例的入口,而不提供构造方法。 - 为什么要使用synchronized 修饰getInstance方法?
这个也和java中的线程安全有关,synchronized 的作用方式和volatile不同,假设有线程A和线程B同时调用getInstance方法,那么synchronized关键字就可将线程A访问时线程B就处于阻塞状态,等线程A使用完毕后再执行这段代码,这样就避免了同一时间段多个线程对单例进行操作,以此达到线程安全的目的。
饿汉式单例
public class User {
private static final User instance=new User();
private User(){}
public static User getInstance(){
return instance;
}
}
饿汉式单例特点,也就是在最开始我们就创建了一个静态的变量对象供使用,而并非等到我们调用getInstance时才开始创建实例,而以后也不再改变,因此也是线程安全的。 经过上述的两种写法的比较,在日常的开发过程中笔者个人认为使用懒汉式单例较为合适。
单例模式就给大家总结到这里啦,觉得写的还不错的记得喜欢~