几个参考地址:
http://www.ibm.com/developerworks/cn/java/j-dcl.html
http://www.iteye.com/topic/537563
http://www.iteye.com/topic/260515
http://www.iteye.com/topic/344876
http://www.iteye.com/topic/60179
关键字: singleton 单例 写法 双锁 线程安全
饿汉式单例类
Java代码
1. public class Singleton
2. {
3. private Singleton(){
4.
5. }
6.
7. private static Singleton instance = new Singleton();
8.
9. private static Singleton getInstance(){
10. return instance;
11. }
12. }
public class Singleton
{
private Singleton(){
}
private static Singleton instance = new Singleton();
private static Singleton getInstance(){
return instance;
}
}
饿汉式提前实例化,没有懒汉式中多线程问题,但不管我们是不是调用getInstance()都会存在一个实例在内存中
内部类式单例类
Java代码
1. public class Singleton
2. {
3. private Singleton(){
4.
5. }
6.
7. private class SingletonHoledr(){
8. private static Singleton instance = new Singleton();
9. }
10.
11. private static Singleton getInstance(){
12. return SingletonHoledr.instance;
13. }
14. }
public class Singleton
{
private Singleton(){
}
private class SingletonHoledr(){
private static Singleton instance = new Singleton();
}
private static Singleton getInstance(){
return SingletonHoledr.instance;
}
}
内部类式中,实现了延迟加载,只有我们调用了getInstance(),才会创建唯一的实例到内存中.并且也解决了懒汉式中多线程的问题.解决的方式是利用了Classloader的特性.
懒汉式单例类
Java代码
1. public class Singleton
2. {
3. private Singleton(){
4.
5. }
6.
7. private static Singleton instance;
8. public static Singleton getInstance(){
9. if(instance == null){
10. return instance = new Singleton();
11. }else{
12. return instance;
13. }
14. }
15. }
public class Singleton
{
private Singleton(){
}
private static Singleton instance;
public static Singleton getInstance(){
if(instance == null){
return instance = new Singleton();
}else{
return instance;
}
}
}
在懒汉式中,有线程A和B,当线程A运行到第8行时,跳到线程B,当B也运行到8行时,两个线程的instance都为空,这样就会生成两个实例。解决的办法是同步:
可以同步但是效率不高:
Java代码
1. public class Singleton
2. {
3. private Singleton(){
4.
5. }
6.
7. private static Singleton instance;
8. public static synchronized Singleton getInstance(){
9. if(instance == null){
10. return instance = new Singleton();
11. }else{
12. return instance;
13. }
14. }
15. }
public class Singleton
{
private Singleton(){
}
private static Singleton instance;
public static synchronized Singleton getInstance(){
if(instance == null){
return instance = new Singleton();
}else{
return instance;
}
}
}
这样写程序不会出错,因为整个getInstance是一个整体的"critical section",但就是效率很不好,因为我们的目的其实只是在第一个初始化instance的时候需要locking(加锁),而后面取用 instance的时候,根本不需要线程同步。
于是聪明的人们想出了下面的做法:
双检锁写法:
Java代码
1. public class Singleton{
2. private static Singleton single; //声明静态的单例对象的变量
3. private Singleton(){} //私有构造方法
4.
5. public static Singleton getSingle(){ //外部通过此方法可以获取对象
6. if(single == null){
7. synchronized (Singleton.class) { //保证了同一时间只能只能有一个对象访问此同步块
8. if(single == null){
9. single = new Singleton();
10. }
11. }
12. }
13. return single; //返回创建好的对象
14. }
15. }
public class Singleton{
private static Singleton single; //声明静态的单例对象的变量
private Singleton(){} //私有构造方法
public static Singleton getSingle(){ //外部通过此方法可以获取对象
if(single == null){
synchronized (Singleton.class) { //保证了同一时间只能只能有一个对象访问此同步块
if(single == null){
single = new Singleton();
}
}
}
return single; //返回创建好的对象
}
}
思路很简单,就是我们只需要同步(synchronize)初始化instance的那部分代码从而使代码既正确又很有效率。
这就是所谓的“双检锁”机制(顾名思义)。
很可惜,这样的写法在很多平台和优化编译器上是错误的。
原因在于:instance = new Singleton()这行代码在不同编译器上的行为是无法预知的。一个优化编译器可以合法地如下实现instance = new Singleton():
1. instance = 给新的实体分配内存
2. 调用Singleton的构造函数来初始化instance的成员变量
现在想象一下有线程A和B在调用getInstance,线程A先进入,在执行到步骤1的时候被踢出了cpu。然后线程B进入,B看到的是instance 已经不是null了(内存已经分配),于是它开始放心地使用instance,但这个是错误的,因为在这一时刻,instance的成员变量还都是缺省值,A还没有来得及执行步骤2来完成instance的初始化。
当然编译器也可以这样实现:
1. temp = 分配内存
2. 调用temp的构造函数
3. instance = temp
如果编译器的行为是这样的话我们似乎就没有问题了,但事实却不是那么简单,因为我们无法知道某个编译器具体是怎么做的,因为在Java的memory model里对这个问题没有定义。
双检锁对于基础类型(比如int)适用。很显然吧,因为基础类型没有调用构造函数这一步。
分享到:
相关推荐
单例模式是软件设计模式中的一种,用于控制类的实例化过程,确保一个类只有一个实例,并提供全局访问点。在Java中,实现单例模式有多种方法,每种方法都有其特点和适用场景。以下是对这六种常见单例模式实现方式的...
Java设计模式之单例模式的七种写法 单例模式是一种常见的设计模式,它确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机的驱动程序对象常...
在Unity游戏开发中,单例模式是一种常用的编程设计模式,它确保一个类只有一个实例,并提供一个全局访问点。这种模式在处理需要跨场景共享数据的情况时尤其有用,因为Unity的场景切换可能导致对象被销毁,而单例则...
单例模式的实现通常包括以下几个关键步骤: 1. **声明一个类方法**:`+ (instancetype)sharedInstance;` 这个方法返回单例对象,是全局获取单例的主要途径。 2. **私有化初始化方法**:`- (instancetype)init NS_...
单例模式是一种常用的软件设计模式,在很多编程语言中都有广泛的应用。在Python中实现单例模式不仅有助于提高代码的可读性和可维护性,还能有效控制资源的使用。本文将详细介绍Python中实现单例模式的三种方法:使用...
在Java语言中,实现单例模式主要有以下几种方式: 1. 饿汉式(Eager Initialization) 饿汉式单例模式在类加载的时候就已经进行了实例化,因此它不需要考虑多线程同步的问题。这种方式在类加载时就完成了初始化,...
单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。...2、具体单例模式的几种模式 第一种单例模式 //非线程安全写法 static UserHelper * helper = nil; + (UserH
需要注意的是,虽然提供了`{providedIn: 'root'}`的方式,但文档中明确说明这个属性并不直接与单例模式有关系,它仅仅是服务提供的一种写法。 在实验中,发现即使服务是懒加载的子模块和组件,当通过`app.module....
以下是根据标题和描述中提到的几种设计模式进行的详细解释: 1. **单例模式**:单例模式确保一个类只有一个实例,并提供全局访问点。这种模式在需要频繁创建和销毁对象,且只允许有一个实例的情况下非常有用,如...
1. 单例模式:了解单例模式的几种写法,包括懒汉式、饿汉式、双重检查锁定式等。 2. JDK 中的设计模式:了解 JDK 中的设计模式,包括 IO 中的装饰模式和设配器模式等。 3. 框架中的设计模式:了解常用的设计模式,...
【06期】单例模式有几种写法? 【07期】Redis中是如何实现分布式锁的? 【08期】说说Object类下面有几种方法呢? 【09期】说说hashCode() 和 equals() 之间的关系? 【10期】Redis 面试常见问答 【11期】分布式...
17. **单例设计模式**:单例模式确保一个类只有一个实例,并提供一个全局访问点。它通常通过私有构造方法、静态变量和静态工厂方法实现。 在学习Java基础时,理解并掌握这些概念是至关重要的,它们构成了编写高效、...
以下是几种实现方式: 1. **懒汉式** ```java public class Singleton { private static Singleton singleton = new Singleton(); private Singleton() {} public static Singleton getSingleton() { ...
这里我们可能会遇到以下几种常见的设计模式: 1. **单例模式**:购物车在整个应用中应当是唯一的,无论用户在哪个页面,购物车的数据都应保持一致。单例模式确保了购物车对象的全局唯一性,避免了多次实例化导致的...
10. **设计模式**:常见的23种设计模式,如单例模式、工厂模式、观察者模式等,是解决常见问题的成熟解决方案。 11. **注解(Annotation)**:用于提供元数据,增强代码的功能和可读性。 12. **Lambda表达式**:...
6. **单例模式的几种写法:** 单例模式保证一个类只有一个实例,并提供一个全局访问点。常见的单例实现方式有饿汉式、懒汉式、枚举类型以及利用双重检查锁定机制等。 7. **web.xml加载顺序:** 在Web应用中,web....
1. **单例模式**:通过`Context.getSharedPreferences()`获取的SharedPreferences对象是单例的,意味着在整个应用中只会有一个实例。这样确保了数据的一致性,避免了多个副本可能导致的冲突。 2. **编辑器模式**:`...
10. **设计模式**:熟悉常见的设计模式,如单例模式、工厂模式、观察者模式等,以及它们在实际开发中的应用。 11. **数据库操作**:SQL基础,ADO.NET或Entity Framework的使用,以及数据库事务处理。 12. **Web...