设计模式是对已有问题固定的解决方法的总结。
单例模式: (单例:单个实例)
单例模式保证只有一个实例,就要保证外界不能随便的new这个对象,所以要
私有化构造方法。
私有化构造方法后就是把
new这个对象控制权收回了,只能在类内部去实例化这个对象,
让类自身负责保存他的唯一实例。
单例模式(Singleton)保证一个类仅有一个实例,并提供一个访问他的全局访问点。
保证类仅有一个实例最好的办法就是,让类自身负责保存他的唯一实例。这个类可以保证没有其他实例被创建,并且他可以提供一个访问该实例的方法。
从时间空间上看:以空间换时间
从线程安全上看:安全的
所以又叫“饿汉式”(还没有使用就实例化了)
public class Singleton {
//3、定义一个变量来存储创建好的类实例
//直接在这里创建类实例,由虚拟机来保证只会创建一次
//这个类加载到内存的时候就会创建唯一的一份实例
private static final Singleton instance = new Singleton();
//1.私有化构造方法,好在内部控制创建实例的数目
private Singleton() {
}
//2、定义一个方法来为客户端提供类实例
//这个方法需要定义成类方法,也就是要加static
public static Singleton getInstance() {
//4、直接使用已经创建好的实例
return instance;
}
}
从时间空间上看:以时间换空间
从线程安全上看:不安全的(所以要加锁synchronized)
所以又叫“懒汉式”(也就是在用到的时候才去实例化)
public class Singleton1 {
//3、定义一个变量来存储创建好的类实例
//因为这个变量要在静态方法中使用,所以需要加上static修饰
private static Singleton1 instance = null;
//1.私有化构造方法,好在内部控制创建实例的数目
private Singleton1() {
}
//2、定义一个方法来为客户端提供类实例
//这个方法需要定义成类方法,也就是要加static
public synchronized static Singleton1 getInstance() {
//4、判断这个实例是不是有值
if (instance == null) {
//5、如果没有,就创建一个类实例,并把值
//赋给存储类实例的变量
instance = new Singleton1();
}
return instance;
}
}
加锁有线程安全的问题:
Singleton singleton1 = Singleton.
getInstance();
Singleton singleton2 = Singleton.
getInstance();
System.
out.println(singleton1 == singleton2);
//true 是同一个对象
被volatile修饰的变量的值,将不会被本地线程缓存所以对该变量的读写都是直接操作共享内存,从而保证多个线程能正确的处理改变量。volatile一个线程修改了值,其他线程可以读取的到。
如果实例存在就没有必要走同步的必要,如果实例不存在才会进入同步块。
这样只会在第一次创建的时候同步一次,其余的时候不需要同步。
第二重检查是因为:当A线程执行 new Singleton()时候,B线程正在执行第一重检查if(instance == null)此时B线程会进入,
所以在synchronized中要再做一次检查。因为instance是volatile修饰的所以A线程new Singleton修改了instance的时候,
在B线程中能读取到instance不是null。