1.单例模式是什么?
定义:
保证一个类中在任何情况下只有一个实例,
并且提供一个全局访问点。
单例模式主要特点:
1、构造方法私有化;
2、实例化的变量引用私有化;
3、获取实例的方法共有。
2.单例模式有哪些?
1.饿汉式(静态常量)
public class HungrySingleton1 {
//1.私有创建实例化对象
private static final HungrySingleton1 instance = new HungrySingleton1();
//2.私有化构造
private HungrySingleton1(){
}
//3.提供公共静态访问方法,返回实例对象
public static HungrySingleton1 getInstance(){
return instance;
}
}
优点:
类加载的时候实例化,避免了线程同步问题
缺点:
如果从头到尾没有使用过实例,会造成内存浪费
结论:
可以使用,但可能会浪费资源
2.饿汉式(静态代码块)
public class HungrySingleton2 {
//1.创建对象实例
private static HungrySingleton2 instance;
//2.私有化构造器
private HungrySingleton2(){}
//3.静态代码块中创建对象
static {
instance=new HungrySingleton2();
}
//3.提供公共静态访问方法,返回对象实例
public static HungrySingleton2 getInstance(){
return instance;
}
}
结论:
区别是在静态代码块中创建实例对象,优点和缺点同上,可能浪费内存资源。
3.懒汉式(线程不安全)
public class LazySingleton1 {
//1.声明私有变量
private static LazySingleton1 instance;
//2.私有构造
private LazySingleton1(){}
//3.提供公共静态方法,使用时才创建对象
public static LazySingleton1 getInstance(){
if (instance == null){
return instance = new LazySingleton1();
}
return instance;
}
}
优点:
有懒加载的作用,但只能在单线程中使用
缺点:
多线程中,一个线程进入if语块,还没有来得及往下执行,
另一个线程通过了if语句,会产生多个实例,违反了一个类中保证只有一个实例的原则,多线程中不可以使用
结论:
实际开发中中不推荐使用
4.懒汉式(线程安全,同步方法)
public class LazySingleton2 {
private static LazySingleton2 instance;
//2.私有构造
private LazySingleton2(){}
//3.提供公共静态方法,使用时才创建对象
// 加了同步关键字,解决了线程安全问题
public static synchronized LazySingleton2 getInstance(){
if (instance == null){
return instance = new LazySingleton2();
}
return instance;
}
}
优点:
懒加载,解决了线程安全问题
缺点:
每个线程想获得实例的时候,都要执行同步方法,方法同步效率低
结论:
实际开发中不推荐这种方式
5.懒汉式(线程安全,同步代码块)
public class LazySingleton3 {
//1.声明私有化静态变量
private static LazySingleton3 instance;
//2.私有构造
private LazySingleton3(){}
//3.提供公共静态方法,使用时才创建对象
// 加了同步代码块,解决了线程安全问题
public static LazySingleton3 getInstance() {
if (instance == null) {
synchronized (LazySingleton3.class) {
return instance = new LazySingleton3();
}
}
return instance;
}
}
结论:
不推荐使用
**
6.双重检查方式
**
public class DoubleCheckSingleton {
//1.声明私有静态同步变量
private static volatile DoubleCheckSingleton instance;
//2.私有化构造
private DoubleCheckSingleton(){}
//3.提供公共静态方法,懒加载
//加入双重检查代码,解决线程安全
public static synchronized DoubleCheckSingleton getInstance() {
if (instance == null) {
synchronized (DoubleCheckSingleton.class) {
if (instance == null) {
instance = new DoubleCheckSingleton();
}
}
}
return instance;
}
}
优点:
1.多线程开发中经常使用,使用了两次if判断,保证了线程的安全。
2.实例化代码只用执行一次,后面再次访问,
判断if(instance==null)直接return实例,
避免反复进行方法同步。
3.延迟加载,效率较高
结论:
实际开发中推荐使用这种方式。
7.静态内部类方式
public class StaticClassSingleton {
//1.声明静态同步变量
private static volatile StaticClassSingleton instance;
//2.私有化构造
private StaticClassSingleton(){}
//3.定义静态内部类中静态属性
private static class SingletonInstance{
private static final StaticClassSingleton INSTANCE = new StaticClassSingleton();
}
//4.提供一个公共静态方法
public static synchronized StaticClassSingleton getInstance(){
return SingletonInstance.INSTANCE;
}
}
优缺点:
1.使用类装载机制保证初始化实例时只有一个线程
2.静态内部类在类装载时不会立即实例化,
需要的时候才调用方法,装载静态内部类,完成实例化。
3.类的静态属性只有在类第一次加载时初始化,JVM帮助保证了线程的安全性,类初始化时,别的线程无法进入。
结论:
线程安全,延迟加载,效率高,推荐使用
8.枚举方式
public enum EnumSingleton {
INSTANCE;
public EnumSingleton getInstance(){
return INSTANCE;
}
}
优缺点:
1.可以避免多线程同步问题,避免反射攻击,防止反序列化重新创建新的对象。
结论:
推荐使用
3.单例模使用注意事项
1.单例模式保证了内存中一个类只存在一个对象,节省了系统资源,
对于一些频繁创建销毁的的对象,可以使用单例模式。
2.当要实例化一个类的时候,可以使用获取对象的方法,而不是new出来。
3.单例模式的使用场景:工具类,数据库源,session工厂等。