完美解决单例设计模式中懒汉式线程安全的问题

首先写个单例:

public class SingleDemo {
  private static SingleDemo s = null;
  private SingleDemo(){}
  public static SingleDemo getInstance(){
    if(s == null){
      s = new SingleDemo();
    }
    return s;
  }
} 

写个测试类:

public class ThreadDemo3 { 

  public static void main(String[] args) {
    SingleDemo s1 = SingleDemo.getInstance();
    SingleDemo s2 = SingleDemo.getInstance();
    System.out.println(s2 == s2);
  }
}

运行结果一直都是true,说明单线程下是没问题的,下面写个多线程来访问单例

public class ThreadTest implements Runnable {
  //存放单例对象,使用Set是为了不存放重复元素
  public Set<SingleDemo> singles = new HashSet<SingleDemo>();
  @Override
  public void run() {
    //获取单例
    SingleDemo s = SingleDemo.getInstance();
    //添加单例
    singles.add(s);
  }
}

使用多线程并发访问单例:

public class ThreadDemo3 { 

  public static void main(String[] args) {
//   SingleDemo s1 = SingleDemo.getInstance();
//   SingleDemo s2 = SingleDemo.getInstance();
//   System.out.println(s2 == s2);
    ThreadTest t = new ThreadTest();
    new Thread(t).start();
    new Thread(t).start();
    new Thread(t).start();
    new Thread(t).start();
    new Thread(t).start();
    new Thread(t).start();
    new Thread(t).start();
    new Thread(t).start();
    System.out.println(t.singles);
  }
}

运行结果如下:
[com.persagy.thread.SingleDemo@1bc4459, com.persagy.thread.SingleDemo@150bd4d]

[com.persagy.thread.SingleDemo@12b6651]

说明有线程并发访问安全问题,获取的不一定都是同一个实例

如何解决线程安全问题呢?

当然使用同步锁机制了啊

下面改进单例:

public class SingleDemo {
	private static SingleDemo s = null;
	private SingleDemo(){}
	public static synchronized SingleDemo getInstance(){
		if(s == null){
			s = new SingleDemo();
		}
		return s;
	}
}

加入同步函数后线程安全问题解决了

运行多次都是获取同一个实例,不会出现2个实例的情况了

[com.persagy.thread.SingleDemo@12b6651]

但是在多线程并发访问的情况下,每个线程每次获取实例都要判断下锁,效率比较低,为了提高效率,我加入了双重判断的方法,解决了效率的问题

代码如下:

public class SingleDemo {
	private static SingleDemo s = null;
	private SingleDemo(){}
	public static SingleDemo getInstance(){
		/*如果第一个线程获取到了单例的实例对象,
		 * 后面的线程再获取实例的时候不需要进入同步代码块中了*/
		if(s == null){
			//同步代码块用的锁是单例的字节码文件对象,且只能用这个锁
			synchronized(SingleDemo.class){
				if(s == null){
					s = new SingleDemo();
				}
			}
		}
		return s;
	}
}

用这种方式解决了懒汉式的线程安全问题,也提高了效率,但是在实际开发中还是用饿汉式的比较多,毕竟这个代码比较多,比较繁琐。

以上就是小编为大家带来的完美解决单例设计模式中懒汉式线程安全的问题全部内容了,希望大家多多支持我们~

(0)

相关推荐

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

    概念: java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例.饿汉式单例.登记式单例三种. 单例模式有一下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建自己的唯一实例. 3.单例类必须给所有其他对象提供这一实例. 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例.在计算机系统中,线程池.缓存.日志对象.对话框.打印机.显卡的驱动程序对象常被设计成单例.这些应用都或多或少具有资源管理器的功能.每台计算机可以有若干个打印机,但只能有一个Printer

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

    1.饿汉式单例 复制代码 代码如下: public class Singleton {   private final static Singleton INSTANCE = new Singleton(); private Singleton() { } public static Singleton getInstance() {      return INSTANCE;   }} 2.借助内部类属于懒汉式单例,因为Java机制规定,内部类SingletonHolder只有在getInst

  • 完美解决单例设计模式中懒汉式线程安全的问题

    首先写个单例: public class SingleDemo { private static SingleDemo s = null; private SingleDemo(){} public static SingleDemo getInstance(){ if(s == null){ s = new SingleDemo(); } return s; } } 写个测试类: public class ThreadDemo3 { public static void main(String

  • Spring如何解决单例bean线程不安全的问题

    首先我们应该知道线程安全问题一般发生在成员变量上,这是为什么啦? 因为成员变量是存放在堆内存中,而堆内存又是线程共享的,这就造成了线程安全问题 因为Spring中的Bean默认是单例的,所以在定义成员变量时也有可能会发生线程安全问题.下面我们就来研究下如何解决Spring中单例Bean的线程安全问题 @RestController //@Scope("prototype") public class BeanController { private int content=0; //基

  • 浅析Java单例设计模式(自写demo)

    目录 单例模式特点 单例模式优点 实现方式 饿汉式(线程安全) 懒汉式 单例模式特点 1.构造器私有 2.在一个Java应用程序中,可保证只有一个实例对象 3.只提供一个供外界调用的getInstance()方法 单例模式优点 1.减少某些对象的频繁创建,降低系统开销和内存占用 2.外部调用不使用new关键字,降低系统内存的使用频率 3.对于特殊的类,在系统中只能存在一个实例,否则系统无法正常运行,比如Controller 实现方式 这里简单介绍两种实现方式 饿汉式(线程安全) /** * @a

  • 浅谈JAVASE单例设计模式

    简单的说设计模式,其实就是对问题行之有效的解决方式.其实它是一种思想. 1.单例设计模式. 解决的问题:就是可以保证一个类在内存中的对象唯一性.(单个实例) 使用单例设计模式需求:必须对于多个程序使用同一个配置信息对象时,就需要保证该对象的唯一性. 如何保证对象唯一性?                                                      解决步骤: 1.不允许其他程序用new创建该对象.                                    

  • Java之单例设计模式示例详解

    单例设计模式 保证一个类在内存中只能有一个对象. 思路: 1)如果其他程序能够随意用 new 创建该类对象,那么就无法控制个数.因此,不让其他程序用 new 创建该类的对象. 2)既然不让其他程序 new 该类对象,那么该类在自己内部就要创建一个对象,否则该类就永远无法创建对象了. 3)该类将创建的对象对外(整个系统)提供,让其他程序获取并使用. 饿汉式: 一上来我就把对象给你 new 好了,你来了直接就可以拿去"吃"了 懒汉式 (要是有人问单例的延迟加载方式指的就是这种方式) 一开始

  • C++单例设计模式详细讲解

    目录 特殊类设计 只能在堆上创建对象的类 请设计一个类只能在栈上创建对象 请设计一个类不能被拷贝 请设计一个类不能被继承 请设计一个类只能创建一个对象(单例模式) 懒汉模式和饿汉模式的对比 特殊类设计 只能在堆上创建对象的类 请设计一个类,只能在堆上创建对象 实现方式: 将类的构造函数私有,拷贝构造声明成私有.防止别人调用拷贝在栈上生成对象. 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建 class test { public: static test* GetObj() { re

  • python单例设计模式实现解析

    这篇文章主要介绍了python单例设计模式实现解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 所谓单例,就是让类创建对象的时候,在系统中只有唯一的一个实例. (1)定义一个类属性,初始值是None,用于记录单例的引用. (2)重写__new__方法. (3)如果类属性是None,调用父类方法分配空间,并在属性中记录结果. (4)返回属性中记录的对象引用. class MusicPlayer(object): instance = None

  • C++简明图解分析静态成员与单例设计模式

    目录 静态成员概述 静态成员数据 static修饰静态成员函数 const修饰静态成员 const修饰成员函数 静态成员案例 单例模式 静态成员概述 1.静态成员包括静态成员数据.静态成员函数 2.成员数据.成员函数被 static修饰 就叫静态成员数据.静态成员函数 3.不管这个类创建了多少个对象,静态成员只有一份,这一份被所有属于这个类的对象共享. 4.静态成员 是属于类 而不是具体的某个对象. 5.静态成员 是在定义完类的时候 就存在了. 静态成员数据 静态变量,是在编译阶段就分配空间,对

  • Unity通用泛型单例设计模式(普通型和继承自MonoBehaviour)

    单例模式是设计模式中最为常见的,不多解释了.但应该尽量避免使用,一般全局管理类才使用单例. 普通泛型单例: public abstract class Singleton<T> where T : class, new() { private static T instance = null; private static readonly object locker = new object(); public static T Instance { get { lock (locker)

  • 完美解决UI-Grid表格元素中多个空格显示为一个空格的问题

    UI-Grid中表格数据中如果存在多个连续的空格,会显示为一个空格,解决方法很简单,只需要加上这样一个样式: .ui-grid-cell-contents { white-space: pre !important; } white-space 属性设置如何处理元素内的空白. pre:  空白会被浏览器保留.其行为方式类似 HTML 中的 <pre> 标签. 以上这篇完美解决UI-Grid表格元素中多个空格显示为一个空格的问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多

随机推荐