单例设计模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点
特点:
1、单例类构造方法私有化(private修饰),只能有一个实例;
2、单例类必须自己创建自己的实例化对象(private static类型);
3、单例类必须给其他类提供这个实例(定义一个静态方法)
优点:
1、避免实例化对象的重复创建,不仅减少每次创建对象的时间开销,还可以节约内存空间;
2、避免由于创建多个实例导致某些值不一致的情况
适用情况:
在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。总之,选择单例模式就是为了避免不一致状态,避免政出多头。
1、饿汉式
public class Singleton1 { //将自身的实例对象设置成一个static final属性 private static final Singleton1 instance = new Singleton1(); //私有构造方法 private Singleton1(){ } //公共静态方法返回该类的实例 public static Singleton1 getInstance(){ return instance; } }
在类加载的时候就创建实例,实例在整个程序周期都存在(直到类卸载)
优点:只在类加载的时候创建一次实例,不会存在多个线程创建多个实例的情况,避免多个线程同步的问题
缺点:类加载之后就会被创建,即使没有用到。线程安全,但效率比较低
2、懒汉式
public class Singleton2 { private static Singleton2 instance; private Singleton2(){ } public static Singleton2 getInstance(){ if(instance == null){ instance = new Singleton2(); } return instance; } }
类加载的时候对象不存在,延迟加载方式,需要时再创建。
优点:节约内存,按需创建
缺点:并发环境下可能出现多个实例,线程不安全
3、懒汉式的简单实现
public class Singleton3 { private static Singleton3 instance; private Singleton3(){ } //在getInstance方法上加synchronized同步,但是有开销 public static synchronized Singleton3 getInstance(){ if(instance == null){ instance = new Singleton3(); } return instance; } }
优点:使用synchronized关键字避免多线程访问时,出现多个实例。
缺点:同步方法频繁调用时,效率略低。每次都要同步,影响性能。
4、双重检查锁定
public class Singleton4 { private static Singleton4 instance; private Singleton4(){ } public static Singleton4 getInstance(){ if(instance == null){//1 //只需要在初始化的时候同步,正常的代码执行路径不需要同步 synchronized(Singleton4.class){ if(instance == null){//2第二层校验 instance = new Singleton4(); } } } return instance; } }
假如两个线程A、B,A执行了代码1,if (instance == null)语句,它会认为单例对象没有创建,此时还没来得及创建对象,线程切到B也执行了同样的语句,B也认为单例对象没有创建,然后两个线程依次执行同步代码块,并分别创建了一个单例对象。为了解决这个问题,还需要在同步代码块中增加if (instance == null)语句,也就是上面看到的代码【第二层校验】。
只需要在初始化的时候同步,正常的代码执行路径不需要同步。
缺点:会出现指令重排的情况。
指令重排:
在不改变原语义的情况下,通过调整指令的执行顺序让程序运行的更快。JVM中并没有规定编译器优化相关的内容,也就是说JVM可以自由的进行指令重排序的优化。
为了优化指令,提高程序运行效率。指令重排序包括编译器重排序和运行时重排序。
* JVM规范规定,指令重排序可以在不影响单线程程序执行结果前提下进行
5、双重检查锁定+volatile
public class Singleton5 { private static volatile Singleton5 instance; private Singleton5(){ } public static Singleton5 getInstance(){ if(instance == null){ synchronized(Singleton5.class){ if(instance == null){ instance = new Singleton5(); } } } return instance; } }
volatile禁止指令重排。volatile的另一个语义是保证变量修改的可见性。
双重检查锁定不是线程安全的,如果要用这种方式,需要使用volatile关键字。
使用volatile保证了多线程访问时instance变量的可见性,避免了instance初始化时其他变量属性还没赋值完时,被另外线程调用
6、静态内部类(延迟初始化占位类模式)
public class Singleton6 { private static class InstanceHolder{ public static Singleton6 instance = new Singleton6(); } private Singleton6(){ } public static Singleton6 getInstance(){ return InstanceHolder.instance; } }
该模式引进了一个静态内部类(占位类),在内部类中提前初始化实例,既保证了Singleton实例的延迟初始化,又保证了同步。
这是一种提前初始化(恶汉式)和延迟初始化(懒汉式)的综合模式。
不常用设计模式:
登记式单例:登记式单例实际上维护了一组单例类的实例,将这些实例存放在一个Map(登记薄)中,对于已经登记过的实例,则从Map直接返回,对于没有登记的,则先登记,然后返回。
正确的单例模式有三种:
1、饿汉式---方式一
2、双重检查锁定+volatile---方法五
3、静态内部类(延迟初始化占位类模式)---方法六
线程安全:
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
或者说:一个类或者程序所提供的接口对于线程来说是原子操作,或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题,那就是线程安全的。
双重检查锁定的线程安全
双重检查锁定不是线程安全的,如果要用这种方式,需要使用volatile关键字。
假设没有关键字volatile的情况下,两个线程A、B,都是第一次调用该单例方法,线程A先执行instance = new Instance(),该构造方法是一个非原子操作,编译后生成多条字节码指令,由于JAVA的指令重排序,可能会先执行instance的赋值操作,该操作实际只是在内存中开辟一片存储对象的区域后直接返回内存的引用,之后instance便不为空了,但是实际的初始化操作却还没有执行,如果就在此时线程B进入,就会看到一个不为空的但是不完整(没有完成初始化)的Instance对象,所以需要加入volatile关键字,禁止指令重排序优化,从而安全的实现单例。
相关推荐
入名所示,该文件为最详细的Java单例模式讲解并附有讲解代码。主要讲了单例模式的几种方法,懒汉模式、饿汉模式、静态内部类模式。着重讲解了懒汉模式下怎么实现线程安全。饿汉模式和静态内部类模式如何设置能够避免...
JAVA设计模式之单例模式(完整版)1[定义].pdf
目录 单例模式的概念 单例模式的要点 单例模式类图 单例模式归类 单例模式的应用场景 单例模式解决的问题 单例模式的实现方式 单例模式实现方式对比 单例模式的概念 单例模式,顾名思义就是只有一个实例,并且由它...
Java设计模式是面向对象编程中的重要概念,它们是软件开发中经过验证的、解决常见问题的最佳实践。在这些模式中,单例模式是最为广泛使用的一种。单例模式确保一个类只有一个实例,并提供一个全局访问点,使得在整个...
Java设计模式之单例模式的七种写法 单例模式是一种常见的设计模式,它确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机的驱动程序对象常...
单例模式是软件设计模式中的一种经典模式,它在Java编程中被广泛使用,尤其是在需要控制实例化过程,或者确保某类只有一个实例时。本文将深入探讨Java中的单例模式,帮助你理解其原理和应用。 单例模式的核心思想是...
Java设计模式之单例模式详解 一、单例模式概览 单例模式(Singleton Pattern)是面向对象设计模式中的一种,属于创建型模式。它确保一个类仅有一个实例,并提供一个全局访问点来访问该实例。单例模式的核心在于控制...
计算机后端-Java-图解java设计模式037 单例模式JK.avi
Java设计模式-单例模式详解 单例模式是 Java 设计模式中的一种常用的设计模式,旨在保证一个类仅有一个实例,并提供一个访问它的全局访问点。单例模式的目的是为了保证在一个进程中,某个类有且仅有一个实例。 ...
Java设计模式中的单例模式是一种常用的创建型设计模式,它保证了类只有一个实例,并提供一个全局访问点。这种模式在很多场景下非常有用,比如控制共享资源、管理配置信息等。接下来,我们将深入探讨8种不同的单例...
给同学上课时做的ppt
单例模式是软件设计模式中的一种经典模式,它保证了类只有一个实例存在,并提供一个全局访问点。在Java等面向对象编程语言中,单例模式常用于管理共享资源,如数据库连接池、线程池或者配置文件等。结合工厂模式,...
"设计模式单例模式和工厂模式综合应用"的主题聚焦于两种常用的设计模式:单例模式和工厂模式,并探讨它们如何协同工作来实现高效、灵活的代码结构。这个主题尤其适用于Java编程语言,因为Java的面向对象特性使得设计...
计算机后端-Java-图解java设计模式036 单例(.avi
计算机后端-Java-图解java设计模式038 单例模.avi
计算机后端-Java-图解java设计模式035 单例(静.avi
计算机后端-Java-图解java设计模式034 单例(DoubleC.avi
计算机后端-Java-图解java设计模式032 单例(线程安.avi
计算机后端-Java-图解java设计模式031 单例(线程不安.avi
计算机后端-Java-图解java设计模式029 单例(静态常.avi