线程安全的"懒汉"单例模式
所谓线程不安全实际上就是一段代码在同一时间被两个线程同时执行,导致运行结果与单个线程运行结果不相同
新建一个单例模式类和一个多线程测试类
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;
} }
线程安全的"懒汉"单例模式的更多相关文章
- 饿汉单例模式 and 懒汉单例模式
饿汉单例模式:主要就是利用static关键字,在类加载的时候生成实例,调用效率高 但是如果一直没有调用getInstance方法的话,就会造成资源浪费 具体实现如下: class Single{ pr ...
- C++实现线程安全的单例模式
在某些应用环境下面,一个类只允许有一个实例,这就是著名的单例模式.单例模式分为懒汉模式,跟饿汉模式两种. 首先给出饿汉模式的实现 template <class T> class sing ...
- java23种设计模式(三)单例模式
原文地址:https://zhuanlan.zhihu.com/p/23713957 一.概述 1.什么是单例模式? 百度百科是这样定义的:单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个 ...
- C++ 常用设计模式(学习笔记)
1.工厂模式:简单工厂模式.工厂方法模式.抽象工厂模式 1).简单工厂模式:主要特点是需要在工厂类中做判断,从而创造相应的产品,当增加新产品时,需要修改工厂类. typedef enum { T80 ...
- C++的单例模式与线程安全单例模式(懒汉/饿汉)
1 教科书里的单例模式 我们都很清楚一个简单的单例模式该怎样去实现:构造函数声明为private或protect防止被外部函数实例化,内部保存一个private static的类指针保存唯一的实例,实 ...
- 一天一个设计模式——(Singleton)单例模式(线程安全性)
一.模式说明 有时候,我们希望在应用程序中,仅生成某个类的一个实例,这时候需要用到单例模式. 二.模式类图 三.模式中的角色 Singleton角色,该模式中仅有的一个角色,该角色有一个返回唯一实例的 ...
- C#工具:ASP.NET MVC单例模式(懒汉)实现文件上传
1.SingletonConfigRead帮助类 using System; using System.Collections.Generic; using System.IO; using Syst ...
- 设计模式之单例模式(Singleton)
设计模式之单例模式(Singleton) 设计模式是前辈的一些经验总结之后的精髓,学习设计模式可以针对不同的问题给出更加优雅的解答 单例模式可分为俩种:懒汉模式和饿汉模式.俩种模式分别有不同的优势和缺 ...
- 单例模式——创建型模式01
1. 名称 单例模式(Singleton Pattern):确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类.单例模式是一种对象创建型模式. 2. 问题 ...
随机推荐
- 5月21 汽车查询及批量删除----php方法
---恢复内容开始--- 这个与之前不同是在php中实现了页面的查询,引用AJAX实现批量删除及弹窗的显示 作业要求: 页面显示数据代码: <!DOCTYPE html PUBLIC " ...
- 创建springboot的聚合工程(三)
springboot聚合工程之添加mybatis数据库持久化操作 在boot-polymer-repository工程添加mybatis的相关依赖 <project xmlns="ht ...
- 将你的Vim 打造成轻巧强大的IDE
Vim和Emacs一个称为神之编辑器一个被称为编辑器之神,固然很是夸张,但也足以说明这两 款软件的优秀和在程序员界的地位.但是它们都已漫长的学习曲线让人望而生畏,阻止了大 多数人进入.作为一名几乎完全 ...
- 【LeetCode】最大子序列和
要求时间复杂度 O(n). e.g. 给定数组 [-2,1,-3,4,-1,2,1,-5,4],其中有连续子序列 [4,-1,2,1] 和最大为 6. 我完全没有想法,看了答案. C++实现: int ...
- zzw原创_根据某一文件复制出大量固定位数后缀名的递增的文件
1.trre.sh :根据某一文件复制出大量固定位数后后缀递增的文件. 如将 SPINFO_190516_20170109.001 复制成SPINFO_190516_20170109.002 ...
- Qt_qwt图形开发
QWT,全称是Qt Widgets for Technical Applications,是一个基于LGPL版权协议的开源项目, 可生成各种统计图.它为具有技术专业背景的程序提供GUI组件和一组实用类 ...
- ubuntu分辨率
http://askubuntu.com/questions/235507/xconfig-xrandr-badmatch 先装驱动再说. 今天开机发现ubuntu分辨率不正常只有1024×768, ...
- zabbix3.4.7之Zabbix_Trigger_Function详解
Trigger函数 1.abschange 参数:直接忽略后边的参数 支持值类型:float.int.str.text.log 描述:返回最近获取到的值与之前值的差值的绝对值.对于字符串类型,0表示值 ...
- 1-2Controller之Session
laravel5.5版本. 视频教程是慕课网中的:轻松学会Laravel-表单篇 1-2 /*session简介: 1.由于HTTP协议是无状态(Stateless)的,所以session提供一种保存 ...
- 【原创】QString 函数 replace()indexOf()、 lastindexOf()
1.替换函数 示例: QString x = "Say yes!"; QString y = "no"; x.replace(, , y); // x == & ...