一、单例模式
1.介绍:
作用:
保证一个类只有一个实例,并且只提供一个访问该实例的全局访问点。
常见场景:
Spring中的每个bean
数据库连接池
-
web应用中的servlet
。。。
优点:
- 单例模式只生成一个实例,减少系统开销,提高性能
- 方便共享资源访问
常见五种单例模式实现方式:
- 饿汉式-----------------线程安全、调用效率高、不能延迟加载
- 懒汉式------------------线程安全、调用效率不高、可以延迟加载
- DCL懒汉式--------------------由于jvm底层内部模型原因,不建议使用
- 饿汉式改进-----------------线程安全、调用效率高、可以延迟加载
- 枚举单例-------------------线程安全、调用效率高、不能延迟加载
2.五种单例模式代码
1)饿汉式
/**
*饿汉式-----------------线程安全、调用效率高、不能延迟加载
*/
public class Singleton_01 {
// 1.类初始化创建实例
private static Singleton_01 instance = new Singleton_01();
// 2.私有构造器
private Singleton_01 () {
}
// 3.提供获取该对象的访问方法
public static Singleton_01 getInstance(){
return instance;
}
}
class Test {
public static void main(String[] args) {
Singleton_01 instance1 = Singleton_01.getInstance();
Singleton_01 instance2 = Singleton_01.getInstance();
System.out.println(instance1 == instance2);
}
}
存在的问题: 无论该类是否被调用,都会去开辟空间,容易浪费资源
2) 懒汉式
/**
* 懒汉式
*/
public class Singleton_02 {
// 1.类初始化时候,不立即加载改对象
private static Singleton_02 instance;
// 2.私有构造器
private Singleton_02(){
}
// 3.提供获取该对象的访问方法 ,synchronized效率低
public static synchronized Singleton_02 getInstance(){
if(instance == null){
instance = new Singleton_02();
}
return instance;
}
}
class Test02 {
public static void main(String[] args) {
Singleton_01 instance1 = Singleton_01.getInstance();
Singleton_01 instance2 = Singleton_01.getInstance();
System.out.println(instance1 == instance2);
}
}
存在问题:高并发情况下,效率低下
3)DCL懒汉式
/**
* DCL懒汉式
*/
public class Singleton_03 {
// 1.类初始化时候,不立即加载改对象
private static Singleton_03 instance;
// 2.私有构造器
private Singleton_03(){
}
// 3.提供获取该对象的访问方法
public static Singleton_03 getInstance(){
if(instance == null){
synchronized (Singleton_03.class){
instance = new Singleton_03();
}
}
return instance;
}
}
class Test03 {
public static void main(String[] args) {
Singleton_01 instance1 = Singleton_01.getInstance();
Singleton_01 instance2 = Singleton_01.getInstance();
System.out.println(instance1 == instance2);
}
}
存在问题:可能会出现这个种情况,当第一个用户进行获取实例时候,会进行实例创建,在实例还未创建完成时,紧接着第二个用户也来获取实例,这时用户2发现实例已经不为null,就直接return,事实上用户2得到的实例可能是不完整的。
4)懒汉式改进
/**
* 懒汉式改进
*/
public class Singleton_04 {
// 1.私有构造器
private Singleton_04 () {
}
// 2.内部静态类进行创建对象
private static class InitClass{
private static final Singleton_04 instance = new Singleton_04();
}
// 3.提供获取该对象的访问方法
public static Singleton_04 getInstance(){
return InitClass.instance;
}
}
class Test04 {
public static void main(String[] args) {
Singleton_04 instance1 = Singleton_04.getInstance();
Singleton_04 instance2 = Singleton_04.getInstance();
System.out.println(instance1 == instance2);
// 反射机制,破坏单例
Constructor<Singleton_04> declaredConstructor = Singleton_04.class.getDeclaredConstructor(null);
// 破坏访问权限
declaredConstructor.setAccessible(true);
Singleton_04 instance3 = declaredConstructor.newInstance();
System.out.println(instance1==instance3);
}
}
存在问题:反射机制,任然可以破坏改单例对象。
5)枚举单例
public enum Singleton_05 {
INSTRANCE;
public static Singleton_05 getInstance(){
return Singleton_05.INSTRANCE;
}
}
class Test05 {
public static void main(String[] args) {
Singleton_05 instance = Singleton_05.getInstance();
Singleton_05 instance2 = Singleton_05.getInstance();
System.out.println(instance == instance2);
}
}