采取一定的方法保证某个类在整个软件系统中,只能存在一个实例
使用场景:需要频繁创建和销毁的对象;重量级对象
第一种:饿汉式
/**
* 饿汉式(静态变量)
* @author
*
*/
public class Singleton {
//1.私有化构造
private Singleton() {
}
// 2.提供静态变量,还有一种写法是在静态代码块中新建对象赋值,两种没啥区别
private final static Singleton instance = new Singleton();
//3.对外提供接口
public static Singleton getInstance() {
return instance;
}
}饿汉式:静态变量加载
优点:类装载时完成实例化,避免了线程同步的问题
缺点:如果从始至终没有使用过该对象,就会造成性能浪费,没有达到懒加载的效果
第二种:懒汉式
/**
* 懒汉式
*
* @author
*
*/
public class Singleton {
// 1.私有化构造
private Singleton() {
}
// 2.提供静态变量
private static Singleton instance;
// 3.对外提供接口
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}最初版本的懒汉式
优点:实现了懒加载
缺点:只能在单线程情况下使用,当有多个线程同时进入 instance == null判断,可能会产生多个对象
解决方法:在getInstance方法上直接加synchronized锁,但是效率太低
双检锁的懒汉式:推荐使用
public class Singleton {
// 1.私有化构造
private Singleton() {
//防止反射
if (instance != null) {
throw new RuntimeException("禁止创建");
}
}
// 2.提供静态变量
private static volatile Singleton instance;
// 3.对外提供接口
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}推荐使用:解决了线程安全和懒加载的问题,并且效率比最初版本的懒汉式高得多
使用静态内部类完成单例:推荐使用
public class Singleton {
// 1.私有化构造
private Singleton() {
}
// 2.静态内部类,静态变量变量
public static class SingletonInstance{
private static Singleton INSTANCE = new Singleton();
}
// 3.对外提供接口
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}静态内部类在装载时并不会立即实例化,而是在需要使用他也就是调用 getInstance()的时候才会被初始化,由此实现了懒加载。
类的静态属性只有在类第一次加载的时候初始化,在这里,JVM帮助我们实现了线程安全,在类进行初始化时,别的线程无法进入
使用反射机制,破坏懒汉式单例,可以在构造方法中判断,抛出异常来防止反射破坏单例
public static void destory() throws Exception {
//获取单例对象
Singleton instance = Singleton.getInstance();
//拿到私有化的构造方法
Constructor<? extends Singleton> constructor = instance.getClass()
.getDeclaredConstructor();
//越过语法检查
constructor.setAccessible(true);
//新建第二对象
Singleton newInstance = constructor.newInstance();
//结果为false
System.out.println(instance==newInstance);
}枚举类型的天生单例,可以抗反射和反序列化,推荐使用
public enum SingletonEnum {
//创建一个枚举对象,该对象天生单例
Instance;
}