本文由【程序员伟哥】原创,转载请注明出处,不注明请默念三遍【我爱技术】后转载!
更多精彩请关注微信公众号:【IT殿堂】
可以加我微信一起交流技术:【qqqq123456】
都说单例模式简单,可是简单中藏着大大的不简单。
一、介绍
为了避免某个频繁使用的对象不断地重新创建,我们可以使用单例模式。单例模式可以保证在一个JVM中,只有一个实例存在。
二、实现步骤
1、创建单例类
2、在单例类中,声明 private static 的这个类本体类型的变量。
3、只在这个类中保留private的构造方法
4、写一个静态方法,获取这个类被本体类型变量持有的静态变量实例(若为null需要新建)。
如下图所示:
//第一步,创建单例类
public class Singleton {
//第三步、只在这个类中保留private的构造方法
private Singleton(){}
//第二步、在单例类中,声明 private static 的这个类本体类型的变量。
private static Singleton singleton = null;
//写一个静态方法,获取这个类被本体类型变量持有的静态变量实例(若为null需要新建)。
public static Singleton getInstance(){
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
哇塞,单例模式 果然简单,到此万事大吉了!
那么你太天真了!
写一个Test类,如下:
/**
* @Title Test.java
* @Package com.buckyball.dp.singleton
* @author Roy
* @email 574613441@qq.com
* @weixin qqqq123456
* @date 2018年6月28日 下午8:09:06
* @Desc
*/
package com.buckyball.dp.singleton;
/**
* @Title Test.java
* @Package com.buckyball.dp.singleton
* @author Roy
* @email 574613441@qq.com
* @weixin qqqq123456
* @date 2018年6月28日 下午8:09:06
* @Desc
*/
public class Test {
public static Singleton ssingleton;
/**
* @param args
*/
public static void main(String[] args) {
Thread thread1 = new Thread(new Runnable(){
@Override
public void run() {
System.out.println("thread1 run");
Singleton singleton = Singleton.getInstance();
System.out.println("thread1 singleton = "+singleton);
ssingleton = singleton;
}
});
thread1.setName("thread1");
Thread thread2 = new Thread(new Runnable(){
@Override
public void run() {
System.out.println("thread2 run");
Singleton singleton = Singleton.getInstance();
System.out.println("thread2 singleton = "+singleton);
ssingleton = singleton;
}
});
thread2.setName("thread2");
Thread thread3 = new Thread(new Runnable(){
@Override
public void run() {
System.out.println("thread3 run");
Singleton singleton = Singleton.getInstance();
System.out.println("thread3 singleton = "+singleton);
ssingleton = singleton;
}
});
thread3.setName("thread3");
thread1.start();
thread2.start();
thread3.start();
}
}
连续运行两次运行输出的结果如下:很明显,如果有并发线程同时调用获取单例,那么是否获取到的是同一单例,那么就看天意了!显然作为一个靠谱的程序是不能这么做的。
thread1 run
thread2 run
thread3 run
thread1 singleton = com.buckyball.dp.singleton.Singleton@13c339f
thread2 singleton = com.buckyball.dp.singleton.Singleton@ba8af9
thread3 singleton = com.buckyball.dp.singleton.Singleton@ba8af9
thread1 run
thread2 run
thread3 run
thread2 singleton = com.buckyball.dp.singleton.Singleton@fa0094
thread3 singleton = com.buckyball.dp.singleton.Singleton@fa0094
thread1 singleton = com.buckyball.dp.singleton.Singleton@fa0094
如何解决?
1、对 getInstance 方法加 synchronized 关键字修饰
/**
* @Title Singleton.java
* @Package com.buckyball.dp.singleton
* @author Roy
* @email 574613441@qq.com
* @weixin qqqq123456
* @date 2018年6月28日 下午8:05:57
* @Desc
*/
package com.buckyball.dp.singleton;
/**
* @Title Singleton.java
* @Package com.buckyball.dp.singleton
* @author Roy
* @email 574613441@qq.com
* @weixin qqqq123456
* @date 2018年6月28日 下午8:05:57
* @Desc
*/
public class Singleton1 {
private Singleton1(){}
private static Singleton1 singleton = null;
public static synchronized Singleton1 getInstance(){
if(singleton == null){
singleton = new Singleton1();
}
return singleton;
}
}
无论运行多少次,妥妥的每次都是一样的
thread1 run
thread3 run
thread2 run
thread1 singleton = com.buckyball.dp.singleton.Singleton1@ba8af9
thread2 singleton = com.buckyball.dp.singleton.Singleton1@ba8af9
thread3 singleton = com.buckyball.dp.singleton.Singleton1@ba8af9
这样写的问题:
synchronized关键字锁住的是这个对象,这样的用法,在性能上会有所下降,因为每次调用getInstance(),都要对对象上锁,事实上,只有在第一次创建对象的时候需要加锁,之后就不需要了,所以,这个地方需要改进:。
于是看到有人推荐这么写:妥妥的告诉你,给你个大大的叉。synchronized不能锁null对象。
public static Singleton2 getInstance() {
if (singleton == null) {
synchronized (singleton) { //这里会报空指针java.lang.NullPointerException
if (singleton == null) {
singleton = new Singleton2();
}
}
}
return singleton;
}
2、直接声明属性的时候就创建对象
public class Singleton3 {
private Singleton3(){}private static Singleton3 singleton = new Singleton3();public static Singleton3 getInstance(){return singleton;}}
输出如下:
thread1 run
thread2 run
thread3 run
thread1 singleton = com.buckyball.dp.singleton.Singleton3@46b10e8e
thread3 singleton = com.buckyball.dp.singleton.Singleton3@46b10e8e
thread2 singleton = com.buckyball.dp.singleton.Singleton3@46b10e8e
源码地址:https://github.com/tianshanaoxue/design-pattern.git
喜欢我的文章,请微信搜索公众账号:【IT殿堂】,会定期更新原创、系列文章
关注后回复【java】、【Android】、【c++】等关键词有惊喜哦。
也可以加我微信:qqqq123456