设计模式学习之单例模式
单例模式
单例模式属于创建类型的一种常用的软件设计模式。通过单例模式的方法创建在当前进程中有且只有的一个实例(根据需求不同,也可以是在一个线程中有且只有一个实例)
主要意图:有且只有一个实例
主要解决:类的频繁创建与销毁
使用地点:想要控制实例的数量,节省系统资源
实现单例模式有六种实现方法:
1. 单例模式之饿汉式单例
是否多线程安全:是
优点:没有加锁但是线程安全
缺点:浪费内存,容易产生垃圾对象
重点:饿汉式线程安全
线程安全的主要是因为会在声明类的时候就会创建内部私有对象,不会因为多线程而产生多个对象
代码如下:
/**
* 饿汉式单例模式
* @author wt
*/
public class SingletonPatternHunger {
/**内部私有静态对象*/
private static SingletonPatternHunger singleton = new SingletonPatternHunger();
/**私有化无参构造方法*/
private SingletonPatternHunger(){}
/**获取对象接口*/
public static SingletonPatternHunger getSingleton() {
return singleton;
}
}
2. 单例模式之懒汉式单例
懒汉式单例模式我认为是分为三种,分别是线程不安全的简单懒汉式,线程安全的方法锁懒汉式以及理论上线程安全的双检索懒汉式
2.1 线程不安全的简单懒汉式单例
是否多线程安全:否
优点:最基本的实现方法,可以在单线程中实现单例
缺点:多线程不安全
代码:
/**
* 懒汉式单例模式
* @author wt
*/
public class SingletonPatternLazy {
/**先声明静态私有对象*/
private static SingletonPatternLazy lazy;
/**静态构造方法*/
private SingletonPatternLazy(){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
/**异常信息,建议使用开源的log包来显示异常*/
e.printStackTrace();
}
System.out.println("生成了一次对象");
}
/**
* 简单懒汉式单例获取对象接口
* 线程不安全
*/
public static SingletonPatternLazy getLazy1(){
if (lazy == null) {
/**判断是否有对象,如果没有就创建对象*/
lazy = new SingletonPatternLazy();
}
return lazy;
}
}
2.2 线程安全的方法锁懒汉式
是否多线程安全:是
优点:第一次调用时才会初始化,避免内存浪费
缺点:每次获取对象都要进锁,影响效率
代码:
/**
* 懒汉式单例模式
* @author wt
*/
public class SingletonPatternLazy {
/**先声明静态私有对象*/
private static SingletonPatternLazy lazy;
/**静态构造方法*/
private SingletonPatternLazy(){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
/**异常信息,建议使用开源的log包来显示异常*/
e.printStackTrace();
}
System.out.println("生成了一次对象");
}
/**
* 方法锁懒汉式单例获取对象接口
* 线程安全,但是太影响效率
*/
public synchronized static SingletonPatternLazy getLazy2(){
if (lazy == null) {
/**判断是否有对象,如果没有就创建对象*/
lazy = new SingletonPatternLazy();
}
return lazy;
}
}
2.3 双检索懒汉式单例模式
双检索单例模式其实也是根据懒汉式单例模式进行的改变
jdk版本:1.5+
是否多线程安全:加上volatile关键字是线程安全的
优点:第一次调用时才会初始化,避免内存浪费。进行了判断,不会每次获取对象实例都进入锁
缺点:需要额外代码才可以实现反序列化和反射
重点:volatile
/**
* 懒汉式单例模式
* @author wt
*/
public class SingletonPatternLazy {
/**
* 先声明静态私有对象,重点volatile
* 如果没有这个关键字,那么就不是线程安全的,有几率出现错误
*/
private volatile static SingletonPatternLazy lazy1;
/**静态构造方法*/
private SingletonPatternLazy(){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
/**异常信息,建议使用开源的log包来显示异常*/
e.printStackTrace();
}
System.out.println("生成了一次对象");
}
/**
* 双检索懒汉式单例获取对象接口
* 理论上线程安全,但是需要在声明对象时,加上volatile关键字
*/
public static SingletonPatternLazy getLazy3(){
if (lazy1 == null) {
synchronized(SingletonPatternLazy.class){
if (lazy1 == null){
/**判断是否有对象,如果没有就创建对象*/
lazy1 = new SingletonPatternLazy();
}
}
}
return lazy1;
}
}
3. 静态内部类单利模式
是否多线程安全:是
优点:可以有效的实现懒加载
缺点:不能防止反射与序列化的破坏,并且只适用于静态域,如果要在实例域进行延迟加载建议使用双检锁单例
代码:
/**
* 内部类单例模式
* @author wt
*/
public class SingletonPatternInner {
/**私有化构造方法*/
private SingletonPatternInner(){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
/**异常信息,建议使用开源的log包来显示异常*/
e.printStackTrace();
}
/**用来测试多线程调用后生成对象的次数*/
System.out.println("生成了一次对象");
};
/**获取内部类中生成的对象*/
public static SingletonPatternInner getSingleton(){
return SingletonHolder.Singletonholder;
}
/**在内部类中生成对象*/
private static class SingletonHolder{
private static final SingletonPatternInner Singletonholder= new SingletonPatternInner();
}
}
4. 枚举单例
单例模式的最佳实现方法,可以有效的阻止反射和序列化破坏
参考链接(推荐):我做认为讲解枚举最好的博客,里面也包含枚举单例的讲解
jdk版本:1.5+
是否多线程安全:是
优点:单例模式的最佳实现方法,可以阻止反射和序列化攻击
缺点:在需要反射调用时会报错
代码:
/**
* 枚举单例模式
* @author wt
*/
public enum SingletonPatternEnum {
/**静态常量对象*/
INSTANCE;
/**实验数据*/
private String name;
/**获取name*/
public String getName() {
return name;
}
/**输入name*/
public void setName(String name) {
this.name = name;
}
}
1175

被折叠的 条评论
为什么被折叠?



