那什么是单例模式:确保一个类只有一个实例,并提供一个全局访问点。
是不是看起来很正式,哈哈哈~
也就是说让一个类运行时只产生一个对象。
单例模式可以说是众多设计模式中实现较为简单的一种设计模式。
既然比较简单,就话不多说,贴代码上来就一目了然了~
下面说这几种单例模式的实现:
- 懒汉式
- 饿汉式
- 双重检查式
- 内部类式
- 枚举方式
1、饿汉式
注意事项:
1)一个私有的构造器、获取类实例的静态方法
2)对象用private、static、final
关键字修饰
3)浪费内存
4)线程安全
class Singleton {
//私有构造器,确报外面不能 new 对象
private Singleton() {}
//造成内存浪费,每次进来先加载,再使用
private static final Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
线程安全这里说一嘴:一般在Java 里面,static
修饰的东西最先加载、只被加载一次。进来这个类,不管是线程1、线程2、线程3等等等等,instance
已被加载过,就只会返回同一个类的实例。
浪费内存也是在这里:如果这个单例模式的类中还有其它代码,此时我并不想调用这个实例,但它却被加载了。
2、懒汉式
注意事项:
1)构造器私有、静态方法获取类的实例
2)static
修饰的对象
线程不安全
单线程下不影响
class Singleton {
private Singleton() {}
private static Singleton instance;
public static Singleton getInstance() {
if (instance == null) {//1
instance = new Singleton();
}
return instance;
}
}
在1
处判断之后,某个线程因为某种情况搁置了;再来另一个线程判断instance == null
;这两个线程会得到不一样的对象。
线程安全
class Singleton {
private Singleton() {}
private static Singleton instance;
public synchronized static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
3、双重检查式、DCL
注意事项:
1)私有构造器
2)实例用volatile、static
关键字修饰
3)线程安全
class Singleton {
private Singleton() {}
private static volatile Singleton instance;
public static Singleton getInstance() {
if (instance == null) {//1
synchronized (Singleton.class) {
if (instance == null) {//2
instance = new Singleton();
}
}
}
return instance;
}
}
双重检查好处是什么呢?
没有1
的判空条件,势必每个线程都要获取锁,紧接着再去执行其他操作。进行判断以后,后来来的线程就判断一次然后走开,不用加锁、释放锁;
1
处操作的不足时,有可能在某个时刻有两个线程不分先后判空 instance == null
;
然后线程1获取锁创建一个对象、线程2获取锁会创建一个新的对象,这两个对象肯定不一样;
再在2
处判断一次,保证了线程安全,提高了程序性能。由于instance
被 volatile
关键字修饰,一经更改,背的线程就都能注意到。
4、静态内部类式
注意事项:
1)私有构造器
2)私有的静态内部类
3)线程安全
class StaticSingleton {
private StaticSingleton() {}
private static class Singleton {
private static final StaticSingleton instance = new StaticSingleton();
}
public static StaticSingleton getInstance() {
return Singleton.instance;
}
}
为什么是线程安全的呢?第一、类加载的时候是线程安全的;第二:加载一个类时,如果没有使用其内部类,该内部类是不会被加载的。内部类被加载的时候参考第一条。
5、枚举方式
注意事项:
1)无
2)推荐使用
enum Singleton {
INSTANCE;
//下面可以有其它方法、常量等
}
//使用
Singleton singleton = Singleton.INSTANCE;
singleton.xxx;