JAVA设计模式-单例模式
单例模式
类只能有一个实例,在内存中会创建并且只创建一次对象。所有其他类或者其他需要调用的地方都是用这一个对象,可以防止频繁创建对象,内存占用高。特点:只能有一个实例,并且能够自行创建这个实例的类。
实现
饿汉模式
写法一
介绍
在类的加载时就已经创建好对象,线程是安全的,但是会浪费资源。参考源码:JDK1.8 com.sun.glass.ui.monocle.KeyInput类
代码示例
public class Singleton {
/**
* 私有的构造方法,可以防止外部调用时new进行创建对象
*/
private Singleton(){};
/**
* 创建私有的对象
*/
private static Singleton singleton = new Singleton();
/**
* 提供公共的对外的获取方法
* @return
*/
public static Singleton getInstance(){
return singleton;
}
}
写法二
介绍
在类的加载时就已经创建好对象,此处是使用静态代码块进行创建,线程是安全的。
代码示例
public class Singleton {
/**
* 私有的构造方法,可以防止外部调用时new进行创建对象
*/
private Singleton(){};
/**
* 创建私有的对象
*/
private static Singleton singleton = null;
static {
singleton = new Singleton();
}
/**
* 提供公共的对外的获取方法
* @return
*/
public static Singleton getInstance(){
return singleton;
}
}
懒汉模式
写法一
介绍
在第一次使用时进行创建对象,如果多个线程同时调用了getInstance()方法,可能会创建多个对象,线程是不安全的。
代码示例
public class Singleton {
/**
* 私有的构造方法,可以防止外部调用时new进行创建对象
*/
private Singleton(){};
/**
* 创建私有的对象,注意此处不进行new创建
*/
private static Singleton singleton;
/**
* 提供公共的对外的获取方法
* @return
*/
public static Singleton getInstance(){
// 多个线程同时执行这边时,可能会创建多个对象
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
写法二
介绍
这种写法也是在第一次调用时进行创建对象,但是在该方法上增加了synchronized同步锁,这样就可以保证只会有一个线程执行。线程是安全的,但是synchronized在1.6之前性能比较差,1.6之后进行了优化,性能提升,但是此处为了保证线程安全,使用synchronized,还是多少会影响性能。
代码示例
public class Singleton {
/**
* 私有的构造方法,可以防止外部调用时new进行创建对象
*/
private Singleton(){};
/**
* 创建私有的对象,注意此处不进行new创建
*/
private static Singleton singleton;
/**
* 提供公共的对外的获取方法
* @return
*/
public static synchronized Singleton getInstance(){
// 第一次调用时进行创建对象
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
写法三
介绍
这种写法采用双重锁的方式,进行判断并创建对象。线程是不安全的。
分析线程不安全原因:首先在内存中创建对象,需要进行
①分配内存地址
②初始化对象
③设置对象指向刚刚分配的内存地址
但是在编译器、指令集并行、内存中都可能进行指令重排序。如果发生指令重排序,对于单线程来说,如果执行①③②和执行①②③的结果是一样的,但是如果是多线程,在线程A执行完①③之后,如果线程B进入到第一个if语句,则会判断singleton已经指向一个地址,不等于null,则直接返回,此时返回的对象是还未进行初始化的空对象。
代码示例
public class Singleton {
/**
* 私有的构造方法,可以防止外部调用时new进行创建对象
*/
private Singleton(){};
/**
* 创建私有的对象,注意此处不进行new创建
*/
private static Singleton singleton;
/**
* 提供公共的对外的获取方法
* @return
*/
public static Singleton getInstance(){
if(singleton == null){
synchronized (Singleton.class){
if(singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
}
写法四
介绍
在写法三的基础上,增加volatile,volatile可以禁止指令重排序并且保证共享变量不同线程之间的可见性。
代码示例
public class Singleton {
/**
* 私有的构造方法,可以防止外部调用时new进行创建对象
*/
private Singleton(){};
/**
* 创建私有的对象,注意此处不进行new创建, 使用volatile
*/
private volatile static Singleton singleton;
/**
* 提供公共的对外的获取方法
* @return
*/
public static Singleton getInstance(){
if(singleton == null){
synchronized (Singleton.class){
if(singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
}
关注微信公众「平哥技术站」, 每日更新,在手机上阅读所有教程,随时随地都能学习。
觉得写的还不错的小伙伴,请作者喝杯咖啡☕ ,支持一下。😊
如有侵权请立即与我们联系,我们将及时处理,联系邮箱:865934097@qq.com。
评论区