概念:
在Java应用程序中,一个类Class只有一个实例存在
运用:
1)系统资源,如文件路径,数据库链接,系统常量等
2)全局状态化类,类似AutomicInteger的使用
优缺点:
1)节省内存有利于垃圾回收
2)只能使用在特定的环境下,受限制于JVM和容器
单例作用范围的前提是在一个ClassLoad下。所以像分布式应用EJB就要用其它的方式来解决单例问题。
Demo:
分别列出多种实现方式,各分析其优缺点
1)静态成员直接初始化,或者在静态代码块初始化都可以
class Singleton{
private Singleton(){}
private static final Singleton singleton = new Singleton();
public static Singleton getInstance(){return singleton;}
}
该实现只要在一个ClassLoad下就会提供一个对象的单例。但是美中不足的是,不管该资源是否被请求,它都会创建一个对象,占用jvm内存。从lazy initialization思想出发,出现了下2的写法
2)根据lazy initialization思想,使用到时才初始化。
class Singleton{
private Singleton(){}
private static Singleton singleton ;
public static synchronized Singleton getInstance(){
if(singleton==null)
singleton = new Singleton();
return singleton;
}
}
该实现方法加了同步锁,可以有效防止多线程在执行getInstance方法得到2个对象。
缺点:只有在第一次调用的时候,才会出现生成2个对象,才必须要求同步。而一旦singleton 不为null,系统依旧花费同步锁开销,有点得不偿失。
因此再改进出现写法3
3)在2的基础上改进,改进标准:尽量减少锁资源(主要体现在执行时间,所占内存等)
class Singleton{
private Singleton(){}
private static Singleton singleton ;
public static Singleton getInstance(){
if(singleton==null)//1
synchronized(Singleton.class){//2
singleton = new Singleton();//3
}
return singleton;
}
}
这种写法减少了锁开销,但是在如下情况,却创建了2个对象:
a:线程1执行到1挂起,线程1认为singleton为null
b:线程2执行到1挂起,线程2认为singleton为null
c:线程1被唤醒执行synchronized块代码,走完创建了一个对象
d:线程2被唤醒执行synchronized块代码,走完创建了另一个对象
所以看出这种写法,并不完美。
4)为了解决3存在的问题,引入双重检查锁定
public static Singleton getInstance(){
if(singleton==null)//1
synchronized(Singleton.class){//2
if(singleton==null)//3
singleton = new Singleton();//4
}
return singleton;
}
在同步锁代码块内部,再判断一次对象是否为null,为null才创建对象。这种写法已经接近完美:
a:线程1执行到1,已经进入synchronized的时候,线程挂起,线程1占有Singleton.class资源锁;
b:线程2执行到1,当它准备synchronized块时,因为Singleton.class被占用,线程2阻塞;
c:线程1被唤醒,判断出对象为null,执行完创建一个对象
d:线程2被唤醒,判断出对象不为null,不执行创建语句
如此分析,发现似乎没问题。
但是实际上并不能保证它在单处理器或多处理器上正确运行;
问题就出现在singleton = new Singleton()这一行代码。它可以简单的分成如下三个步骤:
mem= singleton();//1
instance = mem;//2
ctorSingleton(instance);//3
这行代码先在内存开辟空间,赋给singleton的引用,然后执行new 初始化数据,但是注意初始化是要消耗时间。如果此时线程3在执行步骤1的时候,发现singleton 为非null,就直接返回,那么线程3返回的其实是一个没构造完成的对象。
我们期望1,2,3 按照反序执行,但是实际jvm内存模型,并没有明确的有序指定。
这归咎于java的平台的内存模型允许“无序写入”。
5)在4的基础上引入volatile
代码如下:
class Singleton{
private Singleton(){}
private static volatile Singleton singleton ;
public static Singleton getInstance(){
if(singleton==null)//1
synchronized(Singleton.class){//2
if(singleton==null)//3
singleton = new Singleton();
}
return singleton;
}
}
Volatile 变量具有 synchronized
的可见性特性,但是不具备原子特性。这就是说线程能够自动发现 volatile 变量的最新值。
而volatile使用时有明确的规定:
-
对变量的写操作不依赖于当前值;
-
该变量没有包含在具有其他变量的不变式中;
—— 只有在状态真正独立于程序内其他内容时才能使用 volatile。
但是5的写法,虽然理论上似乎可以解决无序写入问题。实际上并非如此。
(我个人觉得这里对volatile语法说的不够详细,想知道详细的可以看这篇转帖Java 理论与实践: 正确使用 Volatile 变量
)
小结:
1)使用同步锁方法,内部锁存在不安全。
2)静态成员直接初始化。
分享到:
相关推荐
为了解决这个问题,我们可以采用以下几种策略: 1. **懒汉式(线程不安全)**:在首次调用时才初始化单例,但这种方式在多线程环境下可能不安全。两个线程可能同时进入if语句块,分别创建单例,从而产生多个实例。 ...
在Java编程领域,设计模式是一种经过验证的、通用的解决方案,用于解决软件设计中常见的问题。以下是关于这七种设计模式的详细解释和实例: 1. 单例模式(Singleton): 单例模式确保一个类只有一个实例,并提供一...
单态模式(Singleton模式)是Java设计模式中的一种,它的主要目标是确保一个类在整个应用程序中只有一个实例存在。这种模式的应用场景广泛,特别是在需要全局共享的资源管理、配置中心、日志服务等场合非常常见。 ...
在Java中,实现单例模式主要有以下几种方法: 1. **懒汉式**:也称为延迟加载模式,即在需要的时候才创建单例对象。 2. **饿汉式**:在类装载时就创建单例对象。 3. **双重检查锁定**:一种高效的懒汉式单例实现...
以下是根据提供的内容对几种常见设计模式的详细说明: 1. **Singleton(单例模式)**: - 单例模式确保一个类只有一个实例,并提供全局访问点。这种模式常用于配置管理、线程池、缓存管理等场景。 - 形式一:饿汉...
在Java中,实现单例主要有以下几种方式: - 饿汉式(Eager Initialization):在类加载时就初始化,确保单例对象的唯一性。这种方式线程安全,但可能会浪费内存,因为即使没有使用,单例也会被创建。 ```java ...
使用 Java 解析 XML 的方式有多种,例如使用 DOM、SAX 等解析器。 9. EJB 基本架构 EJB(Enterprise JavaBeans)是一种用于构建 enterprise 应用的 Java 技术。 10. 数字型校验 如何校验数字型?例如使用 ...
│ 164个完整Java代码.zip │ J2EE综合--Struts常见错误的全面汇总.txt │ java程序员面试资料.zip │ JAVA笔试题(上海释锐).pdf │ MIME简介.txt │ SCJP试题详解.pdf │ SQL面试题_心灵深处.htm │ Struts+...
在Android开发过程中,经常使用的几种设计模式包括单例模式、观察者模式、工厂模式、装饰器模式等。每种模式都有其适用场景和独特优势,通过合理的运用,可以显著提升项目的质量和效率。 ### 单例模式详解 #### ...
XML解析是Java中的一种重要技术,用于解析XML文件。XML解析有多种方法,包括DOM解析、SAX解析等。 12. Open Source项目: Open Source项目是指免费、开放的软件项目,包括Apache、Spring、Hibernate等多种项目。 ...
以上就是对JAVA 23种模式中提及的几种设计模式的详细解析。这些模式在实际开发中有着广泛的应用,它们帮助开发者设计出更灵活、可维护的代码结构。了解并熟练应用这些模式,能极大地提高软件的可扩展性和可复用性。
为了保证在多线程环境中也能正确地实现单例模式,通常会采用以下几种方法: 1. **双重检查锁定(Double-Checked Locking)**: - 这种方式是在第一次实例化时进行同步,之后不再同步。 - 代码示例: ```java ...
以下是对给定文件中提到的几种Java设计模式的详细解析。 #### 1. 单例模式 (Singleton Pattern) 单例模式是一种常用的对象创建型模式,其目的是确保一个类只有一个实例,并提供一个全局访问点。实现单例模式的关键...
XML解析有哪几种?** 主要有DOM(Document Object Model)、SAX(Simple API for XML)和StAX(Streaming API for XML)三种。 **7. 简述AJAX** AJAX(Asynchronous JavaScript and XML)是一种在无需重新加载整个...
### 从追MM谈Java的23种设计模式 #### 1. FACTORY(工厂模式) 工厂模式是一种常用的创建型设计模式,它提供了一个创建对象的接口,但允许子类决定实例化哪一个类。工厂方法使得一个类的实例化延迟到其子类。 **...
5. **其他设计模式**:除了以上几种,还有Builder模式(用于复杂对象的构建),Prototype模式(用于复制或克隆对象),Decorator模式(用于动态地给对象添加职责),Facade模式(提供一个统一的接口,用来访问子系统...
除了以上几种模式,还包括以下设计模式的Java实现: 5. **AbstractFactory模式**:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类。 6. **Builder模式**:将复杂对象的构建与它的表示分离,...
根据部分文件内容的描述,我们可以看到几种常见的实现单例模式的方式: 1. **饿汉式** 这是最简单的一种实现方式,它在类加载时就完成了实例化,因此是线程安全的,但缺点是在类初始化时就完成了实例化,可能会...
本文将详细解析标题为“23种设计模式实例(JAVA实现)”的压缩包中所涉及的设计模式,以及如何通过Java语言来实现它们。我们将主要关注以下几个设计模式:Adapter、Chain of Responsibility 和 Singleton,这些都是...
解析XML文档有哪几种方式? 117 七. 流行的框架与新技术 117 1、谈谈你对Struts的理解。 117 2、谈谈你对Hibernate的理解。 118 3、AOP的作用。 118 4、你对Spring的理解。 118 5、谈谈Struts中的Action servlet。 ...