网络销售网站设置,百度广州分公司总经理,大安区网站建设,电子商务网站开发课程设计目录 1.软件设计模式的概念
2.设计模式分类
2.1 创建型模式
2.2 结构型模式
2.3 行为型模式
3.单例设计模式
3.1 单例模式的结构 3.2 单例模式的实现 3.2.1 饿汉式-方式1#xff08;静态变量方式#xff09; 3.2.2 懒汉式-方式1#xff08;线程不安全#xff09;
3.…目录 1.软件设计模式的概念
2.设计模式分类
2.1 创建型模式
2.2 结构型模式
2.3 行为型模式
3.单例设计模式
3.1 单例模式的结构 3.2 单例模式的实现 3.2.1 饿汉式-方式1静态变量方式 3.2.2 懒汉式-方式1线程不安全
3.2.3 懒汉式-方式2线程安全
3.3 单例模式的优点和缺点 1.软件设计模式的概念
软件设计模式Software Design Pattern又称设计模式是一套被“反复使用”、“多数人知晓的”、“代码设计经验的总结”。它描述了在软件设计过程中的一些不断重复发生的问题以及该问题的解决方案。也就是说它是解决特定问题的一系列套路是“前辈们的代码设计经验的总结”具有一定的普遍性可以反复使用。
2.设计模式分类
2.1 创建型模式
用于描述“怎样创建对象”它主要特点是“将对象的创建与使用分离”。GoF书中提供了单例、原型、工厂方法、抽象工厂、建造者五种创建型模式。
2.2 结构型模式
用于描述如何将类或对象按某种布局组成更大的结构GoF书中提供了代理、适配器、桥接、装饰、外观、享元、组合等 7 种结构型模式。
2.3 行为型模式
用于描述类或对象之间怎样相互协作共同完成单个对象无法单独完成的任务以及怎样分配职责。GoF四人组书中提供了模板方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录、解释器11 种行为型模式。
3.单例设计模式
单例模式Singleton Pattern是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类该类负责创建自己的对象同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式可以直接访问不需要实例化该类的对象。
3.1 单例模式的结构
单例模式的主要有以下角色
单例类。只能创建一个实例的类.访问类。使用单例类 3.2 单例模式的实现
单例模式的设计分为俩种
饿汉式类加载就会导致该单实例对象被创建。懒汉式类加载不会导致该单实例对象被创建而是首次使用该对象时才会被创建。 3.2.1 饿汉式-方式1静态变量方式
/*** 饿汉式* 静态变量创建类的对象*/
public class Singleton {//私有构造方法private Singleton() {}//在成员位置创建该类的对象private static Singleton instance new Singleton();//对外提供静态方法获取该对象public static Singleton getInstance() {return instance;}
}
说明
该方式在成员位置声明Singleton类型的静态变量并创建Singleton类的对象instance。instance对象是随着类的加载而创建的。如果该对象足够大的话而一直没有使用就会造成内存的浪费。 3.2.2 懒汉式-方式1线程不安全
/*** 懒汉式* 线程不安全*/
public class Singleton {//私有构造方法private Singleton() {}//在成员位置创建该类的对象private static Singleton instance;//对外提供静态方法获取该对象public static Singleton getInstance() {if(instance null) {instance new Singleton();}return instance;}
}
说明
从上面代码我们可以看出该方式在成员位置声明Singleton类型的静态变量并没有进行对象的赋值操作那么什么时候赋值的呢当调用getInstance()方法获取Singleton类的对象的时候才创建Singleton类的对象这样就实现了懒加载的效果。但是如果是多线程环境会出现线程安全问题。
3.2.3 懒汉式-方式2线程安全
/*** 懒汉式* 线程安全*/
public class Singleton {//私有构造方法private Singleton() {}//在成员位置创建该类的对象private static Singleton instance;//对外提供静态方法获取该对象public static synchronized Singleton getInstance() {if(instance null) {instance new Singleton();}return instance;}
}
说明
该方式也实现了懒加载效果同时又解决了线程安全问题。但是在getInstance()方法上添加了synchronized关键字导致该方法的执行效果特别低。从上面代码我们可以看出其实就是在初始化instance的时候才会出现线程安全问题一旦初始化完成就不存在了。
3.2.4 懒汉式-方式3双重检查锁
再来讨论一下懒汉模式中加锁的问题对于 getInstance() 方法来说绝大部分的操作都是读操作读操作是线程安全的所以我们没必让每个线程必须持有锁才能调用该方法我们需要调整加锁的时机。由此也产生了一种新的实现模式双重检查锁模式。
/*** 双重检查方式*/
public class Singleton { //私有构造方法private Singleton() {}private static Singleton instance;//对外提供静态方法获取该对象public static Singleton getInstance() {//第一次判断如果instance不为null不进入抢锁阶段直接返回实例if(instance null) {synchronized (Singleton.class) {//抢到锁之后再次判断是否为nullif(instance null) {instance new Singleton();}}}return instance;}
}
说明
双重检查锁模式是一种非常好的单例实现模式解决了单例、性能、线程安全问题上面的双重检测锁模式看上去完美无缺其实是存在问题在多线程的情况下可能会出现空指针问题出现问题的原因是JVM在实例化对象的时候会进行优化和指令重排序操作。
要解决双重检查锁模式带来空指针异常的问题只需要使用 volatile 关键字, volatile 关键字可以保证可见性和有序性。
/*** 双重检查方式*/
public class Singleton {//私有构造方法private Singleton() {}private static volatile Singleton instance;//对外提供静态方法获取该对象public static Singleton getInstance() {//第一次判断如果instance不为null不进入抢锁阶段直接返回实际if(instance null) {synchronized (Singleton.class) {//抢到锁之后再次判断是否为空if(instance null) {instance new Singleton();}}}return instance;}
}
小结
添加 volatile 关键字之后的双重检查锁模式是一种比较好的单例实现模式能够保证在多线程的情况下线程安全也不会有性能问题。 还有这里的private static volatile Singleton singleton null;中的volatile也必不可少volatile关键字可以防止jvm指令重排优化。
在java内存模型中volatile 关键字作用可以是保证可见性或者禁止指令重排。这里是因为 singleton new Singleton() 它并非是一个原子操作事实上在 JVM 中上述语句至少做了以下这 3 件事 第一步是给 singleton 分配内存空间 第二步开始调用 Singleton 的构造函数等来初始化 singleton 第三步将 singleton 对象指向分配的内存空间执行完这步 singleton 就不是 null 了。
这里需要留意一下 1-2-3 的顺序因为存在指令重排序的优化也就是说第 2 步和第 3 步的顺序是不能保证的最终的执行顺序可能是 1-2-3也有可能是 1-3-2。
如果是 1-3-2那么在第 3 步执行完以后singleton 就不是 null 了可是这时第 2 步并没有执行singleton 对象未完成初始化它的属性的值可能不是我们所预期的值。假设此时线程 2 进入 getInstance 方法由于 singleton 已经不是 null 了所以会通过第一重检查并直接返回但其实这时的 singleton 并没有完成初始化所以使用这个实例的时候会报错详细流程如下图所示 这里还说一下volatile关键字的第二个作用保证变量在多线程运行时的可见性
public class Test01 {public static void main(String[] args) throws Exception{T tnew T();t.start();Thread.sleep(2000);System.out.println(主线程设置t线程的参数来止损失);t.setFlag(false);}
}
class T extends Thread{private volatile boolean flagtrue;public void setFlag(boolean flag) {this.flag flag;}Overridepublic void run() {System.out.println(进入run方法);while(flag){}}
} 在 JDK1.2 之前Java的内存模型实现总是从主存即共享内存读取变量是不需要进行特别的注意的。而在当前 的 Java 内存模型下线程可以把变量保存本地内存比如机器的寄存器中而不是直接在主存中进行读写。这就 可能造成一个线程在主存中修改了一个变量的值而另外一个线程还继续使用它在寄存器中的变量值的拷贝造成数 据的不一致。 要解决这个问题就需要把变量声明为 volatile这就指示 JVM这个变量是不稳定的每次使用它都到主存中进行 读取。 3.3 单例模式的优点和缺点 优点单例类只有一个实例节省了内存资源对于一些需要频繁创建销毁的对象使用单例模式可以提高系统性能单例模式可以在系统设置全局的访问点优化和共享数据例如前面说的Web应用的页面计数器就可以用单例模式实现计数值的保存。
缺点单例模式一般没有接口扩展的话除了修改代码基本上没有其他途径。
下一篇软件设计模式-工厂模式-CSDN博客