什么是单例设计模式
某个类在整个系统中,只存在一个实例对象可获取和使用
要点
-
一个类只能有一个实例对象
构造器私有化
-
必须自行创建这个实例
含有一个该类的静态变量来存储这个实例
-
向整个系统提供这个实例
对外提供获取该实例的方式
单例设计模式分类
单例设计模式分为两大类:懒汉式、饿汉式
饿汉式:顾名思义,我现在非常饿,我看到一个面包马上就要把他吃下去。所以在整个系统加载时,不管你用不用得到这个对象,都直接创建。
懒汉式:也挺好理解,我非常懒,有严重拖延症,不到万不得已的时候不干。也就是说,只有当我需要使用这个对象时,才创建它。
饿汉式实现
因为在系统加载时就创建了这个对象,所以饿汉式是线程安全的。有三种方法可以实现饿汉式。
直接实例化饿汉式(简洁直观)
public class Singleton1 {
//2.用一个静态对象存储该实例
public static final Singleton1 INSTANCE = new Singleton1();
//1.构造器私有化
private Singleton1(){
}
}
枚举方式(最便捷)
public enum Singleton2 {
INSTANCE
}
静态代码块饿汉式
其实效果是一样的,不过静态代码块更适合在初始化时设置复杂的参数
如果创建有参构造方法,而我们有希望从外部配置文件读取到参数,那就可以使用静态代码块的方式来创建
public class Singleton3 {
private static final Singleton3 INSTANCE;
static {
INSTANCE = new Singleton3();
}
private Singleton3(){
}
}
懒汉式实现
线程不安全的(适用于单线程)
public class Singleton4 {
//2.用一个静态对象存储该实例
private static Singleton4 INSTANCE;
//1.构造器私有化
private Singleton4(){
}
//3.通过方法来暴露实例
public static Singleton4 getInstance(){
if(INSTANCE == null){
INSTANCE = new Singleton4();
}
return INSTANCE;
}
}
可以通过以下方法来测试线程不安全
public class Singletontest4 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<Singleton4> c = new Callable<Singleton4>() {
@Override
public Singleton4 call() throws Exception {
Singleton4 s = Singleton4.getInstance();
return s;
}
};
ExecutorService es = Executors.newFixedThreadPool(2);
Future<Singleton4> submit1 = es.submit(c);
Future<Singleton4> submit2 = es.submit(c);
Singleton4 s1 = submit1.get();
Singleton4 s2 = submit2.get();
System.out.println(s1);
System.out.println(s2);
}
}
线程安全的(适用于多线程)
线程安不安全,无非就是加一把锁
public class Singleton5 {
//2.用一个静态对象存储该实例
private static Singleton5 INSTANCE;
//1.构造器私有化
private Singleton5(){
}
//3.通过方法来暴露实例
public static Singleton5 getInstance(){
if(INSTANCE == null){
synchronized (Singleton5.class) {
INSTANCE = new Singleton5();
}
}
return INSTANCE;
}
}
静态内部类形式(适用于多线程)
将初始化方法放入一个静态内部类中调用,绝对是线程安全的
public class Singleton6 {
private Singleton6(){
}
private static class Inner{
private static final Singleton6 INSTANCE = new Singleton6();
}
public static Singleton6 getInstance(){
return Inner.INSTANCE;
}
}