单例模式 防止用户可以无止境的new, 就只能生成一个实例,
这种适用于某种情况只需要一个实例,防止多次new造成性能下降
单例模式 必备的两个因素, 私有构造器,和一个静态获取实例的方法
一、懒汉模式(非线程安全)
public class SingleTon {
private static SingleTon sg;
private SingleTon(){
}
public static SingleTon getInstance(){
if(sg==null){
sg = new SingleTon();
}
return sg;
}
这种方式在高并发的情况下,可能生成的实例并不是唯一的,因为在高并发的情况下 可能A用户 发现sg是空的要执行new,但是new 方法还没执行完,B发现sg是空也要去执行new,此时可能new出两个不一样的实例 就违背了 单例模式的初衷
二、懒汉模式 (线程安全)
package config;
public class SingleTon {
private static SingleTon sg;
private SingleTon(){
}
public static synchronized SingleTon getInstance(){
if(sg==null){
sg = new SingleTon();
}
return sg;
}
}
没错就是加个 synchronized 线程同步就不会有 并发造成的线程不安全问题了,但是这样一来 即使你已经生成了一个对象,
每次还是得经过synchronized 会造成不必要的内存开销
三、 饿汉模式
public class SingleTon {
private static SingleTon sg =new SingleTon();
private SingleTon(){
}
public static SingleTon getInstance(){
return sg;
}
}
饿汉模式没有 线程问题,因为在调用getInstance之前 ,在类加载进虚拟机的时候已经生成了一个唯一 的静态实例,
但是这样也有一个问题,就是不管你 调用不调用getInstance 都已经生成一个对象,如果在大量使用单例模式的系统中,
会造成内存的浪费
四、静态内部类模式
public class SingleTon {
private SingleTon(){
}
static class SingeTonHolder{
private static SingleTon st = new SingleTon();
}
public static SingleTon getInstance(){
return SingeTonHolder.st;
}
}
这个模式是线程安全的,并且直到调用getInstance 才会生成实例,所以比较推荐这个模式生成单例
五、枚举模式
/**
* 使用枚举的单例模式
*
* @author yzl
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public class EnumSingleton{
private EnumSingleton(){}
public static EnumSingleton getInstance(){
return Singleton.INSTANCE.getInstance();
}
private static enum Singleton{
INSTANCE;
private EnumSingleton singleton;
//JVM会保证此方法绝对只调用一次
private Singleton(){
singleton = new EnumSingleton();
}
public EnumSingleton getInstance(){
return singleton;
}
}
}
传统的两私有一公开(私有构造方法、私有静态实例(懒实例化/直接实例化)、公开的静态获取方法)涉及线程安全问题(即使有多重检查锁也可以通过反射破坏单例),
目前最为安全的实现单例的方法是通过内部静态enum的方法来实现,因为JVM会保证enum不能被反射并且构造器方法只执行一次。