线程安全的"懒汉"单例模式
所谓线程不安全实际上就是一段代码在同一时间被两个线程同时执行,导致运行结果与单个线程运行结果不相同
新建一个单例模式类和一个多线程测试类
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. 问题 ...
随机推荐
- Hybrid APP架构设计思路
通讯 作为一种跨语言开发模式,通讯层是Hybrid架构首先应该考虑和设计的,往后所有的逻辑都是基于通讯层展开. Native(以Android为例)和H5通讯,基本原理: Android调用H5:通过 ...
- java集合的实现细节--ArrayList和LinkedList
ArrayList和LinkedList的实现差异 List代表一种线性表的数据结构,ArrayList则是一种顺序存储的线性表,ArrayList底层采用动态数组的形式保存每一个集合元素,Link ...
- Leetcode 1004. 最大连续1的个数 III
1004. 最大连续1的个数 III 显示英文描述 我的提交返回竞赛 用户通过次数97 用户尝试次数143 通过次数102 提交次数299 题目难度Medium 给定一个由若干 0 和 1 组成 ...
- zzw原创_LIKE与regexp_like中的_及转义符
1.select table_name from user_tables where table_name like 'MENU%';查出以下表MENUMENUGGG_131MENU_132MENU ...
- 手机验证码JQUERY实现
<!DOCTYPE html> <html> <head> <script src="http://libs.baidu.com/jquery/1. ...
- ActiveMQ 的连接和会话
要了解 connection 和 session 的概念,可以先从 ConnectionState 和 SessionState 入手: // 省略部分代码 public class Connecti ...
- vul/0day/shellcode/payload/poc/exp
vul--泛指漏洞 0day--未公开或虽已公开但还没有修复方法的漏洞 shellcode--远程溢出后执行的那段代码 payload--攻击载荷,送到远端机器执行的整段代码 poc--Proof o ...
- [转]一次CMS GC问题排查过程(理解原理+读懂GC日志)
这个是之前处理过的一个线上问题,处理过程断断续续,经历了两周多的时间,中间各种尝试,总结如下.这篇文章分三部分: 1.问题的场景和处理过程:2.GC的一些理论东西:3.看懂GC的日志 先说一下问题吧 ...
- Sql server中 如何用sql语句创建视图
1.视图的作用 视图的作用: 第一点:使用视图,可以定制用户数据,聚焦特定的数据. 解释: 在实际过程中,公司有不同角色的工作人员,我们以销售公司为例的话, 采购人员,可以需要一些与其有关的数据,而与 ...
- facebook广告上传Invalid appsecret_proof provided in the API argument
Status: 400 Response: { "error": { "message": "Invalid appsecret_proof prov ...