如果要保证系统在一个类最多只能存在一个实例时,我们就需要单例模式。这种情况在应用中经常碰到,例如缓存池、数据库连接池、线程池、一些应用服务实例等等。在多线程环境中。为了保证实例的唯一性其实并不简单。
1、最简单的单例模式
为了限制该类的对象被随意的创建,需要保证该类构造方法是私有的,这样外部类就无法创建该类的对象;另外,为了方便给客户对象提供单例对象的使用,我们为提供一个全局访问点,如下:
package com.pattern.singleton;
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
Singleton类中只有一个构造方法,它是被private修饰的,客户对象无法创建该对象的实例。
我们为此单例实现了一个全局访问点 public static Singleton getInstance()方法。
注意:instance 变量是私有的,外界无法访问。此实现是线程安全的,当多个线程同时去访问该类getInstance()方法时,不会初始化多个不同的对象,因为JVM在加载此类的时候,对于static数据的初始化只能由一个线程执行且仅一次。
2、单例性能-延迟创建
如果出于性能方面的考虑,我们希望延迟实例化单例对象(static属性在加载类时就会被初始化),只有在第一次使用该类的实例时才去实例化。此时我们就可以使用延迟创建,我们可以把单例的实例化过程移至getInstance()方法中,而不是在加载时预先创建。当访问该方法时,首先判断该实例对象是不是已经被实例化过了,如果已被初始化,则直接返回这个对象的引用;否则,创建这个实例并初始化,如下:
package com.pattern.singleton;
public class UnThreadSafeSingleton {
private static UnThreadSafeSingleton instance = null;
public static UnThreadSafeSingleton getInstance() {
if (instance == null) {
instance = new UnThreadSafeSingleton();
}
return instance;
}
}
注意: if(instance == null) 判断是否实例化完成了,该方法不是线程安全的。
2.1、线程安全
在高并发的环境中,getInstance()方法返回了多个指向不同的实例对象,原因如何呢?
Thread1 |
Thread2 |
|
1 if(instance==null)
2
3 instance = new UnThreadSafeSingelton();
4 return instance;
5
6
|
1
2 if(instance==null)
3
4 instance = new UnThreadSafeSingelton();
5 return instance;
6
|
|
如果这两个线程按照上述步骤执行,我们不难发现,在时刻1和2,由于还没创建单例对象,Thread1和Thread2都会进入创建单例的代码快分别创建实例。在时刻3 Thread1创建了一个实例对象,但是Thread2此时无法知道,于是继续创建一个新的实例对象,导致这两个线程持有的实例并非为同一个。
更为糟糕的是,在没有自动内存回收机制的语言平台(C++)会因为我们认为创建了一个单例对象,从而忽略了其他线程所产生的对象,不会手动去回收他们,从而引起内存泄露。
为了解决此类问题,我们给方法添加 synchronized关键字,如下:
package com.pattern.singleton;
public class UnThreadSafeSingleton {
private static UnThreadSafeSingleton instance = null;
public static synchronized UnThreadSafeSingleton getInstance() {
if (instance == null) {
instance = new UnThreadSafeSingleton();
}
return instance;
}
}
这样,再多的线程访问都只会实例化一个单例对象。
3、Double-Check Locking
虽然在多线程环境下是线程安全了,但是在多线程高并发的情况下,给次方法加上synchronized关键字会是的性能大不如前。synchronized关键字对整个getInstance()方法同步是没有必要的:我们只要保证实例化这个对象的那段逻辑被一个线程执行就可以了,而返回引用的那段代码是没有必要同步的。如下:
package com.pattern.singleton;
public class DoubleCheckSingleton {
private volatile static DoubleCheckSingleton instance = null;
public static DoubleCheckSingleton getInstance() {
if (instance == null) { // check if it is created.
synchronized (DoubleCheckSingleton.class) { // synchronized creation block
if (instance == null) { // double check if it is created
instance = new DoubleCheckSingleton();
}
}
}
return instance;
}
}
注意: 在getInstance()方法里,首先判断次实例是否被创建了,如果还没有创建,首先使用synchronized同步实例化代码块。在同步代码块里,还需要再次检查是否已经创建了单例对象,因为:如果没有第二次检查,这是有两个线程 Thread A 和 Thrad B 同时进入该方法,他们都检测到instance 为null 不管那个线程先占据了同步锁,并创建了实例对象,都不会阻止另外一个线程进入实例代码块重新创建实例对象,这样,同样会生成两个实例对象,所以,我们在同步的代码块中,要进行第二次判断,判断该对象是否被创建。
属性instance是被volatile修饰的,因为volatile具有synchronized的可见性特点,也就是说线程能够自动发现volatile变量的最新值。这样,如果instance实例化成功,其他线程便能立刻发现。
4、Initialization on demand holder
package com.pattern.singleton;
public class LazyLoadedSingleton {
private LazyLoadedSingleton() {
}
private static class LazyHolder {
private static final LazyLoadedSingleton instance = new LazyLoadedSingleton();
}
public static LazyLoadedSingleton getInstance() {
return LazyHolder.instance;
}
}
分享到:
相关推荐
单例模式是软件设计模式中的一种,它保证一个类只有一个实例,并提供一个全局访问点。在C++中,实现单例模式有多种方法,我们将会深入探讨这一模式的原理、优缺点以及如何在实际编程中应用。 单例模式的核心在于...
单例模式是一种常用的设计模式,它的核心思想是在整个应用程序中,一个类只能有一个实例存在。单例模式常用于控制资源的共享,例如数据库连接池、日志服务等。单例模式有多种实现方式,常见的包括懒汉式、饿汉式以及...
单例模式(Singleton Pattern)是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点。这种模式常用于需要全局共享资源的场景,比如配置管理、日志记录等。 单例模式的组成 私有构造函数:防止外部...
### 设计模式总结:模板设计模式与单例模式 #### 模板设计模式 模板设计模式是一种行为型设计模式,它定义了一个算法的骨架,并允许子类为算法的某些步骤提供具体的实现。通过这种方式,算法的基本流程保持不变,...
【深入浅出单例Singleton模式】 单例模式是一种在软件设计中常见的设计模式,它的核心目标是确保一个类只有一个实例,并提供一个全局访问点。在Java等面向对象编程语言中,单例模式常用于控制资源的共享,如全局...
在软件设计模式中,单例(Singleton)是一种广泛使用的模式,它确保一个类只有一个实例,并提供全局访问点。这个模式通常用于控制共享资源的访问,比如数据库连接、线程池或者配置对象。以下是对单例模式的详细阐述...
**设计模式——单例模式** 在软件工程中,设计模式是一种在特定场景下解决常见问题的标准方案,可以被复用并提升代码质量。单例模式是设计模式中的一种,它保证一个类只有一个实例,并提供一个全局访问点。这种模式...
Java设计模式之单例模式的七种写法 单例模式是一种常见的设计模式,它确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机的驱动程序对象常...
本次我们将深入探讨两种设计模式——单例模式和装饰模式,它们在Java编程中都有着广泛的应用。 首先,让我们来理解“单例模式”。单例模式是一种创建型设计模式,其核心思想是保证一个类只有一个实例,并提供一个...
单例模式是软件设计模式中的一种经典模式,它在许多场景下被广泛使用,尤其是在需要全局唯一实例的情况下。本文将深入探讨单例模式的概念、作用、实现方式以及其在实际编程中的应用。 单例模式的核心思想是确保一个...
单例模式是软件设计模式中的经典模式之一,其主要目的是控制类的实例化过程,确保在应用程序的整个生命周期中,某个类只有一个实例存在。这样的设计通常适用于那些需要频繁创建和销毁,但资源消耗较大的对象,如...
单例模式是软件设计模式中的一种基础模式,它在Java编程中被广泛应用。单例模式的主要目的是确保一个类只有一个实例,并提供一个全局访问点。这种模式可以有效地控制资源的使用,限制实例的数量,提高性能,尤其是在...
设计模式里面的单例模式程序 package com.rrppff; public class Singleton { private static String name; public static String getName() { return name; } public static void setName(String name) { ...
通过研磨设计模式之单例模式的资料,你可以深入理解单例模式的原理、实现方式及其优缺点,进一步提升自己的编程技能和设计思维。学习并熟练掌握设计模式,对于成为一名优秀的Java开发者至关重要。
**设计模式——单例模式** 单例模式是一种广泛应用于软件设计中的创建型设计模式,它的核心思想是确保一个类只有一个实例,并提供一个全局访问点。这样做的好处在于控制共享资源的访问,比如线程安全的数据库连接池...
Java设计模式是面向对象编程中的重要概念,它们是软件开发中经过验证的、解决常见问题的最佳实践。在这些模式中,单例模式是最为广泛使用的一种。单例模式确保一个类只有一个实例,并提供一个全局访问点,使得在整个...
单例模式(Singleton Pattern)是面向对象设计模式中的一种,属于创建型模式。它确保一个类仅有一个实例,并提供一个全局访问点来访问该实例。单例模式的核心在于控制类的实例化过程,保证在任何情况下都只会创建一...
单例模式是软件设计模式中的一种,属于创建型模式,它的主要目的是确保一个类只有一个实例,并提供一个全局访问点。这种模式在很多场景下都非常有用,例如管理共享资源、配置对象或者缓存服务等。 单例模式的核心...