单例模式
定义
确保一个类只有一个实例,并提供一个全局访问点。
通常要创建对象,基本上是离不开new的。在某些特定的场景下,整个应用的生命周期内只需要一个实例对象,那么new显然已经不适用了。
在之前文章中介绍Hibernate时,就曾经使用过单例模式。在静态代码块中初始化了sessionFactory,显然全局的sessionFactory有且只有一个。
public class HibernateUtils {
private static SessionFactory sessionFactory;
static {
Configuration configuration = new Configuration().configure();
sessionFactory = configuration.buildSessionFactory();
}
private HibernateUtils() {}
public static Session openSession() {
Session session = sessionFactory.openSession();
return session;
}
public static Session getCurrentSession() {
Session session = sessionFactory.getCurrentSession();
return session;
}
}
还有数据库连接时的DataSource等都需要使用单例模式。
如果一个类拥有私有的构造函数,那么它就无法通过new来创建实例对象。因此,声明私有的构造函数是设计单例模式的第一步。
实现方式
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return singleton;
}
}
优点:写法简单,就是在类装载的时候就完成实例化,是线程安全的。
缺点:在类装载的时候就完成实例化,没有达到懒加载的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费。
public class Singleton {
private static Singleton singleton;
static {
singleton = new Singleton();
}
private Singleton() {}
public static Singleton getInstance() {
return singleton;
}
}
优点:有懒加载的效果,在需要时才会实例化,不会造成内存的浪费。
缺点:线程不安全。
public class Singleton {
private static Singleton singleton;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
优点:有懒加载的效果,在需要时才会实例化,不会造成内存的浪费。
缺点:线程不安全。
public class Main {
public static void main(String[] args) {
new Thread(()-> System.out.println(Singleton.getInstance())).start();
new Thread(()-> System.out.println(Singleton.getInstance())).start();
new Thread(()-> System.out.println(Singleton.getInstance())).start();
new Thread(()-> System.out.println(Singleton.getInstance())).start();
new Thread(()-> System.out.println(Singleton.getInstance())).start();
}
}
开启五个线程获取单例对象,结果:
com.xiaobai.singleton.Singleton@581e62ab
com.xiaobai.singleton.Singleton@1f7e6c66
com.xiaobai.singleton.Singleton@1f7e6c66
com.xiaobai.singleton.Singleton@1f7e6c66
com.xiaobai.singleton.Singleton@1f7e6c66
public class Singleton {
private static Singleton singleton;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
优点:有懒加载的效果,在需要时才会实例化,不会造成内存的浪费,同时也是线程安全的。
缺点:使用synchronized同步,会损失部分性能。
public class Singleton {
private volatile static Singleton singleton;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) {
synchronized(Singleton.class) {
singleton = new Singleton();
}
}
return singleton;
}
}
优点:有懒加载的效果,在需要时才会实例化,不会造成内存的浪费。
缺点:线程不安全,虽然用synchronized同步了,但是就算通过if (singleton == null)后任然会存在线程安全问题。
public class Singleton {
private volatile static Singleton singleton;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) {
synchronized(Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
优点:有懒加载的效果,在需要时才会实例化,不会造成内存的浪费;双重检验,是线程安全的。
缺点:使用synchronized同步,会损失部分性能。
public class Singleton {
private Singleton() {}
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
优点:因为是静态内部类,有懒加载的效果,在需要时才会实例化,不会造成内存的浪费,同时也是线程安全的。
public class Singleton {}
public enum ForSingleton {
INSTANCE;
private Singleton singleton;
ForSingleton() {
singleton = new Singleton();
}
public Singleton getInstance() {
return singleton;
}
}
优点:有懒加载的效果,也是线程安全的。
利用枚举类型必须是私有的特点来实现单例模式。