`
一个人旅行
  • 浏览: 91935 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

线程安全的单例模式

阅读更多
最常见的懒汉模式下的核心代码
if(instance == null) { 
    instance = new Singleton(); 
} 

如果一个线程在第二行的赋值语句发生之前切换,那么成员变量instance仍然是null,然后另一个线程可能接下来进入到if块中。在这种情况下,两个不同的单例类实例就被创建。

寻找一种性能改进方法时,你可能会选择像下面这样重写getInstance()方法:
public static Singleton getInstance() { 
   if(singleton == null) { 
      synchronized(Singleton.class) {  
         singleton = new Singleton(); 
      } 
   } 
   return singleton; 
} 

这个代码片段只同步了关键的代码,而不是同步整个方法。然而这段代码却不是线程安全的。考虑一下下面的假定:线程1进入同步块,并且在它给singleton成员变量赋值之前线程1被切换。接着另一个线程进入if块。第二个线程将等待直到第一个线程完成,并且仍然会得到两个不同的单例类实例。

双重加锁检查--》终极解决方案?
public static Singleton getInstance() { 
  if(singleton == null) { 
     synchronized(Singleton.class) { 
       if(singleton == null) { 
         singleton = new Singleton(); 
       } 
    } 
  } 
  return singleton; 
} 

如果两个线程同时访问getInstance()方法会发生什么?想像一下线程1进行同步块马上又被切换。接着,第二个线程进入if 块。当线程1退出同步块时,线程2会重新检查看是否singleton实例仍然为null。因为线程1设置了singleton成员变量,所以线程2的第二次检查会失败,第二个单例类实例也就不会被创建。似乎就是如此。
不幸的是,双重加锁检查不会保证正常工作,因为编译器会在Singleton的构造方法被调用之前随意给singleton赋一个值。如果在singleton引用被赋值之后而被初始化之前线程1被切换,线程2就会被返回一个对未初始化的单例类实例的引用。

May be the final:
public class Singleton { 
   public final static Singleton INSTANCE = new Singleton(); 
   private Singleton() { 
         // Exists only to defeat instantiation. 
      } 
} 

这段代码是线程安全的是因为静态成员变量一定会在类被第一次访问时被创建。你得到了一个自动使用了懒汉式实例化的线程安全的实现。

原文链接:http://www.iteye.com/topic/60179#
分享到:
评论
2 楼 wenlong0898 2013-01-18  
楼主试试运行上面的代码,验证一下文中的这段话:

不幸的是,双重加锁检查不会保证正常工作,因为编译器会在Singleton的构造方法被调用之前随意给singleton赋一个值。如果在singleton引用被赋值之后而被初始化之前线程1被切换,线程2就会被返回一个对未初始化的单例类实例的引用。
1 楼 wenlong0898 2013-01-18  
public class Foo {

    private static Foo inst;

    public Foo() {

        System.out.println(Thread.currentThread().getName() + " 进入 Foo()构造函数,等待5s!");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        Thread.currentThread().yield();
        System.out.println(Thread.currentThread().getName() + " 构造函数放弃Cpu等待下一次调度!");
        
        System.out.println(Thread.currentThread().getName() + " 进入 Foo()构造函数,等待5s!");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        

        System.out.println(Thread.currentThread().getName() + " 构造完成!");

    }

    public static void main(String[] args) {

        Runnable run = new Runnable() {
            int i = 0;

            @Override
            public void run() {
                for (; i < 15; i++) {

                    System.out.println("第" + i + "秒:Foo.inst = " + Foo.inst);
                    try {
                        Thread.currentThread().sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }

        };

        Thread t = new Thread(run);
        t.start();
        
        System.out.println("打印线程启动!");

        Foo.inst = new Foo();

    }

}

相关推荐

    Qt线程安全单例模式写日志模式

    保证一个类只有一个实例,并提供一个访问它的全局访问点,使得系统中只有唯一的一个对象实例,具有线程安全,多线程测试通过。 1.打开日志并创建日志文件夹 默认为程序启动路径 2.清理日志文件下日志数量 默认保留90...

    使用C++11实现线程安全的单例模式

    线程安全的单例模式在多线程环境下尤其重要,因为不正确的实现可能导致多个线程创建多个实例,这违反了单例模式的基本原则。C++11引入了新的特性,如std::mutex和std::call_once,使得实现线程安全的单例模式变得...

    C++两种线程安全的单例模式的实现

    使用"懒汉模式"与"饿汉模式"实现c++的单例模式,并且确保了单例模式的第一次实例化的线程安全,以及程序结束时,单例对象的资源收回,以防内存资源的泄漏

    c++线程安全单例模式

    c++单例模式, 需要boost中的function、bind、shared_ptr支持; 很好用; 下载中含简单的测试代码; 原帖:http://blog.csdn.net/CDScan/archive/2009/11/21/4848084.aspx

    线程安全单例

    然而,在多线程环境下,如果单例模式实现不当,则可能导致线程安全问题。因此,实现线程安全的单例模式就显得尤为重要。 #### 实现方法 给定的代码示例采用了一种称为“懒汉式”的单例模式实现方式,同时利用了...

    多线程单例模式并发访问

    ### 多线程单例模式并发访问 #### 一、多线程基础概念 在讨论多线程单例模式及并发访问之前,我们先来了解一些基本概念。 **进程**和**线程**是计算机科学中的两个核心概念,它们之间的关系紧密而复杂。 - **进程...

    详解python实现线程安全的单例模式

    然而,如果我们想要在类级别实现线程安全的单例模式,就需要考虑多线程环境下的并发问题。 在给出的代码中,首先定义了一个装饰器`Singleton`,它的目的是确保每次调用时返回的是同一个实例。装饰器内部维护了一个...

    Java中懒汉单例设计模式线程安全测试

    Java中懒汉单例设计模式线程安全测试,单例设计模式的测试

    老生常谈C++的单例模式与线程安全单例模式(懒汉/饿汉)

    1 教科书里的单例模式 我们都很清楚一个简单的单例模式该怎样去实现:构造函数声明为private或protect防止被外部函数实例化,内部保存一个private static的类指针保存唯一的实例,实例的动作由一个public的类方法...

    浅议单例模式之线程安全(转)

    在多线程环境下,线程安全的单例模式尤为重要,因为如果不正确实现,可能会导致多个线程同时创建多个实例,违反了单例模式的基本原则。 在Java中,单例模式通常有以下几种实现方式: 1. 饿汉式(静态常量): ...

    C++ 多线程和多线程下的单例模式

    本资源描述了C++11 中多线程的创建,C++11中std命名空间中将boost库中的Thread加入,boost多线程从准标准变为标准,其中还介绍了C++ 多线程下的单例模式的使用,本文档为txt文档

    java多线程之线程安全的单例模式

    在多线程环境下,线程安全的单例模式尤其重要,因为如果不正确地实现,可能会导致多个线程创建多个实例,违反了单例模式的基本原则。本文将详细介绍Java中线程安全的单例模式,包括懒汉式和饿汉式两种实现方式。 1....

    43丨单例模式(下):如何设计实现一个集群环境下的分布式单例模式?1

    线程唯一的单例模式,又称为线程局部单例,是指在同一个线程内保证单例的唯一性,而在不同线程之间可以有各自的实例。实现线程唯一单例通常可以通过使用`ThreadLocal`变量。`ThreadLocal`为每个线程都维护了一个独立...

    单例模式线程安全的三种表达

    单例模式三种线程安全的表达方式,其中枚举方式的单例是最安全的

    线程安全的单例模式的几种实现方法分享

    线程安全的单例模式是设计模式中的一种经典实现,主要目标是在多线程环境下确保一个类只有一个实例,并提供全局唯一的访问点。以下是对几种线程安全单例模式实现方式的详细解释: 1. **饿汉式单例**: 饿汉式单例...

    Java 单例模式线程安全问题

    Java 单例模式线程安全问题详解 Java 单例模式线程安全问题是指在 Java 中实现单例模式时,如何确保线程安全的问题。单例模式是指在整个应用程序生命周期中,只有一个实例存在的设计模式。这种模式可以提高性能,...

    详解C++实现线程安全的单例模式

    总结来说,C++实现线程安全的单例模式通常涉及到对实例化过程的控制,以确保在多线程环境下只有一个实例存在。饿汉模式在类加载时完成实例化,是线程安全的,而懒汉模式需要额外的同步机制如互斥锁来保证线程安全。...

    c++单例模式线程日志类

    在这个特定的场景中,我们讨论的是一个实现了单例模式的日志类,该类专为多线程环境设计,具备日志等级控制、精确的时间戳以及可变长参数和标准格式化输出的功能。 首先,让我们深入了解单例模式。单例模式的主要...

Global site tag (gtag.js) - Google Analytics