所谓线程不安全实际上就是一段代码在同一时间被两个线程同时执行,导致运行结果与单个线程运行结果不相同

新建一个单例模式类和一个多线程测试类

public class TestSingleTon implements Runnable{

	public static void main(String[] args) {
TestSingleTon t1 = new TestSingleTon();
TestSingleTon t2 = new TestSingleTon(); Thread thread1 = new Thread(t1);
Thread thread2 = new Thread(t2);
thread1.start();
thread2.start();
} @Override
public void run() {
System.out.println(SingleTon.getInstance()); } } public class SingleTon {
private static SingleTon singleTon; public static SingleTon getInstance() {
    if(singleTon==null) {
singleTon = new SingleTon();
}
return singleTon;
} }

执行后发现控制台打印了两个不同的对象:

com.wey.demo.SingleTon@22896964
com.wey.demo.SingleTon@1ac5e970

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

解决方案(1):使用同步锁机制,最简单的是在getInstance()方法上加synchronized关键字

public synchronized static SingleTon getInstance() {
if(singleTon==null) {
singleTon = new SingleTon();
}
return singleTon;
}

对于这种方式,有人觉得在多并发的情况下,每次获取实例都要判断锁,效率比较低下,所以就有人想出了这样的办法,双重判断实例,这种大大减少判断同步锁的次数了。所以实际使用中可以推广。

public static SingleTon getInstance() {
if(singleTon==null) {
synchronized (SingleTon.class) {//SingleTon的字节码
if(singleTon==null) {
singleTon = new SingleTon();
}
}
}
return singleTon;
}

同时用volatile关键字修饰singleTon即:

private volatile static Singleton singleTon = null;

完整的代码应该是这样的:

public class SingleTon {
private static SingleTon singleTon; public static SingleTon getInstance() {
  if(singleTon==null) {
synchronized(SingleTon.class) {
if(singleTon==null) {
singleTon = new SingleTon();
}
}
}
return singleTon;
} }
为什么要使用volatile 修饰singleTon?

主要在于singleTon = new Singleton()这句,这并非是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情:

1.给 singleTon 分配内存

2.调用 Singleton 的构造函数来初始化成员变量

3.将singleTon 对象指向分配的内存空间(执行完这步 singleTon  就为非 null 了)。

但是在 JVM 的即时编译器中存在指令重排序的优化。也就是说上面的第二步和第三步的顺序是不能保证的,最终的执行顺序可能是 1-2-3 也可能是 1-3-2。如果是后者,则在 3 执行完毕、2 未执行之前,被线程二抢占了,这时 singleTon  已经是非 null 了(但却没有初始化),所以线程二会直接返回 singleTon ,然后使用,然后顺理成章地报错

解决方案(2):改懒汉式单例为饿汉式单例

public class SingleTon {
private static SingleTon singleTon = new SingleTon(); public static SingleTon getInstance() {
return singleTon;
} }

线程安全的"懒汉"单例模式的更多相关文章

  1. 饿汉单例模式 and 懒汉单例模式

    饿汉单例模式:主要就是利用static关键字,在类加载的时候生成实例,调用效率高 但是如果一直没有调用getInstance方法的话,就会造成资源浪费 具体实现如下: class Single{ pr ...

  2. C++实现线程安全的单例模式

    在某些应用环境下面,一个类只允许有一个实例,这就是著名的单例模式.单例模式分为懒汉模式,跟饿汉模式两种. 首先给出饿汉模式的实现 template <class T> class sing ...

  3. java23种设计模式(三)单例模式

    原文地址:https://zhuanlan.zhihu.com/p/23713957 一.概述 1.什么是单例模式? 百度百科是这样定义的:单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个 ...

  4. C++ 常用设计模式(学习笔记)

    1.工厂模式:简单工厂模式.工厂方法模式.抽象工厂模式 1).简单工厂模式:主要特点是需要在工厂类中做判断,从而创造相应的产品,当增加新产品时,需要修改工厂类. typedef enum { T80 ...

  5. C++的单例模式与线程安全单例模式(懒汉/饿汉)

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

  6. 一天一个设计模式——(Singleton)单例模式(线程安全性)

    一.模式说明 有时候,我们希望在应用程序中,仅生成某个类的一个实例,这时候需要用到单例模式. 二.模式类图 三.模式中的角色 Singleton角色,该模式中仅有的一个角色,该角色有一个返回唯一实例的 ...

  7. C#工具:ASP.NET MVC单例模式(懒汉)实现文件上传

    1.SingletonConfigRead帮助类 using System; using System.Collections.Generic; using System.IO; using Syst ...

  8. 设计模式之单例模式(Singleton)

    设计模式之单例模式(Singleton) 设计模式是前辈的一些经验总结之后的精髓,学习设计模式可以针对不同的问题给出更加优雅的解答 单例模式可分为俩种:懒汉模式和饿汉模式.俩种模式分别有不同的优势和缺 ...

  9. 单例模式——创建型模式01

    1. 名称     单例模式(Singleton Pattern):确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类.单例模式是一种对象创建型模式. 2. 问题    ...

随机推荐

  1. 【CSS】【1】让DIV中的文字换行显示

    <div style="white-space:normal;word-break:break-all;word-wrap:break-word;">data</ ...

  2. Event IO Process

    先了解一下process和event loop EventLoop 除了异步Server和Client库之外,Swoole扩展还提供了直接操作底层epoll/kqueue事件循环的接口.可将其他扩展创 ...

  3. excel导入 导出

    PHP页面 //设置header header("content-Type:text/html;charset=utf-8"); //设置文件大小的限制 ini_set(" ...

  4. 用javascript切换bootstrap的tab

    html: <button class="tabContainer" data-toggle="tab" href="#note" i ...

  5. js浮点数相加、减、乘、除精确计算

    js 浮点数计算时 ,无缘无辜 后边冒出一堆 小数点………… 貌似js本身的问题,类型不定?????? 只能自己写函数处理..  http://blog.csdn.net/w4bobo/article ...

  6. MySQL数据库安装与配置鸡汤

    目录 一.概述 二.MySQL安装 三.安装成功验证 四.NavicatforMySQL下载及使用 一.概述 MySQL版本:5.7.17 下载地址:http://rj.baidu.com/soft/ ...

  7. python 判断变量是否存在 防止报错

    Python判断变量是否存在 方法一:使用try: ... except NameError: .... try: var except NameError: var_exists = False e ...

  8. 五笔xu

      1● 横 a s d f g     半包围 上下 左右   2● 竖 h j k l m 左右 上下 半包围     3● 撇 q w e r t     半包围 上下 左右 4● 捺 y u ...

  9. 【oracle】oracle REGEXP_SUBSTR分割字符串

    REGEXP_SUBSTR的使用:通过REGEXP_SUBSTR进行数据分割: , LEVEL, 'i') AS STR FROM DUAL CONNECT BY LEVEL <= LENGTH ...

  10. 【原创】<Debug> QT头文件

    [Error] No such file or directory [Solution] 参考: http://blog.csdn.net/donglynn/article/details/21804 ...