老大一直说要用这个来做面试题,让面试的人来写一个线程安全的单例模式,感觉自己还没掌握,把 Head first--Design Patterns 找了出来,以下大部分内容抄袭自这本书,略有增删改。
1. 全局变量的缺点:
必须在程序一开始就创建好对象,如果程序在这次的执行过程中又一直没用到它,就非常耗费资源。
2. 经典的单例模式实现:
public class Singleton {
//用一个静态变量来记录Singleton类的唯一实例
private static Singleton uniqueInstance;
private Singleton() {}
//注意这个方法也是静态的
public static Singleton getInstance() {
if(uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
单例常被用来管理共享的资源,例如数据库连接、线程池、缓存、注册表。
单例模式确保一个类只有一个实例,并提供一个全局访问点。
这个模式的问题:在多线程时,并不能保证这个类只被实例化一次。
3. 处理多线程:
public class Singleton {
//用一个静态变量来记录Singleton类的唯一实例
private static Singleton uniqueInstance;
private Singleton() {}
//注意这个方法也是静态的
public static synchronized Singleton getInstance() {
if(uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
通过增加synchronized关键字到getInstance()方法中,迫使每个线程在进入方法之前,要先等别的线程离开该方法。也就是说,不会有两个线程可以同时进入这个方法。
这种方法存在的问题:只有第一次执行此方法时,才真正需要同步。换句话说,一旦设置好uniqueInstance变量,就不再需要同步这个方法了。之后每次调用这个方法,同步都是一种浪费。
4.改善多线程
4.1 如果getInstance()的性能对应用程序不是很关键,就不用优化了
4.2 使用急切创建实例,而不用延迟实例化的做法
public class Singleton {
private static Singleton uniqueInstance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return uniqueInstance;
}
}
标红的语句在静态初始化器(static initializer)中创建单例,这保证了线程安全。
利用这个做法,JVM在加载这个类时马上创建此唯一的单件实例。JVM保证任何线程访问uniqueInstance静态变量之前,一定先创建些实例。
4.3 用“双重检查加锁”,在getInstance()中减少使用同步
首先检查实例是否已经创建,如果尚未创建,才进行同步。这样一来,只有第一次会同步,这正是我们想要的。
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {}
public static Singleton getInstance() {
if(uniqueInstance == null) { //(1)
//只有第一次才彻底执行这里的代码
synchronized() {
//再检查一次
if(uniqueInstance == null)
uniqueInstance = new Singleton();
}
}
return uniqueInstance;
}
}
在最开始如果有1、2、3个线程走到了(1)处,假设1进入了同步块,2、3等待。1实例化后,2进入同步块,发现uniqueInstance已经不为空,跳出同步块。接着3进入,又跳出同步块。
volatile关键字确保:当uniqueInstance变量被初始化成Singleton实例时,多个线程正确地uniqueInstance变量。如果性能是你关心的重点,那么这个做法可以帮你大大地减少getInstance()的时间耗费。
分享到:
相关推荐
保证一个类只有一个实例,并提供一个访问它的全局访问点,使得系统中只有唯一的一个对象实例,具有线程安全,多线程测试通过。 1.打开日志并创建日志文件夹 默认为程序启动路径 2.清理日志文件下日志数量 默认保留90...
线程安全的单例模式在多线程环境下尤其重要,因为不正确的实现可能导致多个线程创建多个实例,这违反了单例模式的基本原则。C++11引入了新的特性,如std::mutex和std::call_once,使得实现线程安全的单例模式变得...
使用"懒汉模式"与"饿汉模式"实现c++的单例模式,并且确保了单例模式的第一次实例化的线程安全,以及程序结束时,单例对象的资源收回,以防内存资源的泄漏
c++单例模式, 需要boost中的function、bind、shared_ptr支持; 很好用; 下载中含简单的测试代码; 原帖:http://blog.csdn.net/CDScan/archive/2009/11/21/4848084.aspx
然而,在多线程环境下,如果单例模式实现不当,则可能导致线程安全问题。因此,实现线程安全的单例模式就显得尤为重要。 #### 实现方法 给定的代码示例采用了一种称为“懒汉式”的单例模式实现方式,同时利用了...
### 多线程单例模式并发访问 #### 一、多线程基础概念 在讨论多线程单例模式及并发访问之前,我们先来了解一些基本概念。 **进程**和**线程**是计算机科学中的两个核心概念,它们之间的关系紧密而复杂。 - **进程...
然而,如果我们想要在类级别实现线程安全的单例模式,就需要考虑多线程环境下的并发问题。 在给出的代码中,首先定义了一个装饰器`Singleton`,它的目的是确保每次调用时返回的是同一个实例。装饰器内部维护了一个...
Java中懒汉单例设计模式线程安全测试,单例设计模式的测试
1 教科书里的单例模式 我们都很清楚一个简单的单例模式该怎样去实现:构造函数声明为private或protect防止被外部函数实例化,内部保存一个private static的类指针保存唯一的实例,实例的动作由一个public的类方法...
实现线程安全的单例模式是C++编程中的一个常见任务。通过使用C++11提供的特性,如静态局部变量初始化和std::call_once,我们可以轻松实现线程安全的单例模式。这些方法不仅保证了单例对象的唯一性,还提高了代码的...
总结来说,单例模式在实现计数器时,可以确保计数器的全局唯一性,同时提供了一种线程安全的方式来管理和访问这个计数器。这种模式在需要全局共享资源或状态,如日志服务、缓存管理、数据库连接池等场景中尤为适用。...
在多线程环境下,线程安全的单例模式尤为重要,因为如果不正确实现,可能会导致多个线程同时创建多个实例,违反了单例模式的基本原则。 在Java中,单例模式通常有以下几种实现方式: 1. 饿汉式(静态常量): ...
本资源描述了C++11 中多线程的创建,C++11中std命名空间中将boost库中的Thread加入,boost多线程从准标准变为标准,其中还介绍了C++ 多线程下的单例模式的使用,本文档为txt文档
在多线程环境下,线程安全的单例模式尤其重要,因为如果不正确地实现,可能会导致多个线程创建多个实例,违反了单例模式的基本原则。本文将详细介绍Java中线程安全的单例模式,包括懒汉式和饿汉式两种实现方式。 1....
线程唯一的单例模式,又称为线程局部单例,是指在同一个线程内保证单例的唯一性,而在不同线程之间可以有各自的实例。实现线程唯一单例通常可以通过使用`ThreadLocal`变量。`ThreadLocal`为每个线程都维护了一个独立...
单例模式三种线程安全的表达方式,其中枚举方式的单例是最安全的
线程安全的单例模式是设计模式中的一种经典实现,主要目标是在多线程环境下确保一个类只有一个实例,并提供全局唯一的访问点。以下是对几种线程安全单例模式实现方式的详细解释: 1. **饿汉式单例**: 饿汉式单例...
Java 单例模式线程安全问题详解 Java 单例模式线程安全问题是指在 Java 中实现单例模式时,如何确保线程安全的问题。单例模式是指在整个应用程序生命周期中,只有一个实例存在的设计模式。这种模式可以提高性能,...