单例
Singleton类被称为单例类,通过使用private的构造函数确保了在一个应用只产生一个实例.
----设计模式之禅
使用场景
在一个系统中,要求一个类有且仅有一个对象,如果出现多个对象就会出现"不良反应",可以采用单例模式,
具体使用场景如下:
- 需要生成唯一序列号的环境
- 创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源.
- 等等
单例的逐渐进化之路
1.饿汉式
/**
* can't lazy load
* 饿汉式,不能懒加载
* @author husky
* @date 2019/5/3 20:42
*/
public class SingletonObject1 {
private static final SingletonObject1 instance = new SingletonObject1();
private SingletonObject1(){
//empty
}
private static SingletonObject1 getInstance(){
return instance;
}
}
2.懒汉式
/**
* 在多线程情况下是不安全的,因为在getIntsance中判断的时候,可能会造成多个实例出现
* 实现懒加载,但线程不安全
* @author husky
* @date 2019/5/3 21:02
*/
public class SingletonObject2 {
private static SingletonObject2 instance;
private SingletonObject2(){
//empty
}
public static SingletonObject2 getInstance(){
if(null == instance){
instance = new SingletonObject2();
}
return instance;
}
}
3.线程安全懒汉式
/**
* 加一把锁可以解决,这把锁是class锁,SingletonObject3.class
* 但是会造成效率低下
* 实现了线程安全,但性能不高
* @author husky
* @date 2019/5/3 21:08
*/
public class SingletonObject3 {
private static SingletonObject3 instance;
private SingletonObject3(){
//empty
}
public synchronized static SingletonObject3 getInstance(){
if(null == instance){
instance = new SingletonObject3();
}
return instance;
}
}
4.double-check
/**
* double check
* 解决了懒加载以及单例,以及性能问题,但是有问题,可能会出现空指针异常
* 在private SingletonObject()会造成fielda或者fieldB未被赋值,导致空指针
* @author husky
* @date 2019/5/3 21:31
*/
public class SingletonObject4 {
private static SingletonObject4 instance;
private int fieldA;
private int fieldB;
private SingletonObject4(){
fieldA = Integer.MIN_VALUE;
fieldB = Integer.MAX_VALUE;
}
public static SingletonObject4 getInstance(){
if(null == instance){
synchronized (SingletonObject4.class){
if(null == instance){
instance = new SingletonObject4();
}
}
}
return instance;
}
}
此处出现的空指针异常,具体原因可以查看 double-check出现的错误
5.double-check volatile
/**
*
* 加入volatile可以避免空指针异常,也就是dcl,但是效率有点低
* @author husky
* @date 2019/5/3 23:12
*/
public class SingletonObject5 {
private static volatile SingletonObject5 instance;
private SingletonObject5(){
}
private static SingletonObject5 getInstance(){
if(null == instance){
synchronized (SingletonObject5.class){
if(null == instance){
return new SingletonObject5();
}
}
}
return instance;
}
}
6.静态内部类
public class SingletonObject6 {
private SingletonObject6(){
}
private static class InstanceHolder {
private final static SingletonObject6 instance = new SingletonObject6();
}
public static SingletonObject6 getInstance(){
return InstanceHolder.instance;
}
}
7.枚举,推荐使用6或7,关于枚举,会在后面博客当中进行分析
import java.util.stream.IntStream;
/**
* 枚举类型
* @author husky
* @date 2019/5/4 14:37
*/
public class SingletonObject7 {
private SingletonObject7(){
}
private enum Singleton {
/**
* instance
* */
INSTANCE;
private final SingletonObject7 instance;
Singleton(){
instance = new SingletonObject7();
}
public SingletonObject7 getInstance(){
return instance;
}
}
public static SingletonObject7 getInstance(){
return Singleton.INSTANCE.getInstance();
}
public static void main(String[] args) {
IntStream.rangeClosed(1,50).forEach(i->{
new Thread(String.valueOf(i)){
@Override
public void run() {
System.out.println(SingletonObject7.getInstance());
}
}.start();
});
}
}