Java线程和多线程(五)——单例类中的线程安全
单例模式是最广泛使用的创建模式之一。在现实世界之中,诸如Databae
的连接或者是企业信息系统(EIS)等,通常其创建都是受到限制的,应该尽量复用已存在对象而不是频繁创建销毁。为了达到这个目的,开发者通常会通过实现单例模式来创建一个wrapper类,来封装资源,限制其运行时所创建对象的个数。
单例中的线程安全
总的来说,开发者一般会按照如下的方式来创建单例的类:
- 使用私有构造函数来避免其它外部引用通过new的方式来创建新的对象引用。
- 声明一个该类的私有静态变量为实例。
- 提供一个公有的静态方法来返回单例的实例。如果实例还没有初始化的话,就将其初始化后再返回实例。
通过上面的步骤,我写了一个如下的单例类:
package com.sapphire.designpatterns;
public class ASingleton {
private static ASingleton instance = null;
private ASingleton() {
}
public static ASingleton getInstance() {
if (instance == null) {
instance = new ASingleton();
}
return instance;
}
}
在上面的代码中,getInstance()
方法不是线程安全的。多线程可以在同一时间访问这个方法,而在最开始的少数线程中,实例没有初始化的时候,多线程可以进入到if代码块来创建多个实例,就破坏了单例模式。
通常来说,有三种方式来让我们保证单例模式的线程安全。
在class加载的时候就创建实例变量
这种实现方式有如下优点:
- 不需要同步即可实现线程安全
- 容易实现
但是也有一些缺点:
- 过早的创建了资源,但是应用可能并不会使用这个资源,造成了资源浪费
- 调用方式无法传入任何参数的,所以我们无法复用这个类。举例来说,如果我们希望有一个单例类能够处理所有的数据库连接信息,并希望能够传入一些数据库信息的话,我们就无法复用这个单例类了。
同步getInstance()
方法
这种方法有如下优点:
- 保证了线程安全
- 调用方可以传入任何参数
- 可以保证延迟初始化
当然这种方法也有一些缺点:
- 因为使用了同步方法,会锁定资源,令所有客户端的请求会优先请求锁,从而降低了性能
- 包含了很多非必要的同步,因为一旦实例创建完成,同步就只是浪费了性能而没有任何作用了
在if代码块中使用同步代码块
优点:
- 保证了线程的安全
- 调用方可以传递参数
- 保证了延迟初始化
- 最小化了同步负载,仅仅在最开始的几个线程请求的时候进行同步操作
淡然也有一定的缺点
- 需要额外的if条件判断
从三种方法来判断,第三种方式应该是最佳的方式来实现同步了,代码大体如下:
package com.sapphire.designpatterns;
public class ASingleton{
private static ASingleton instance= null;
private static Object mutex= new Object();
private ASingleton(){
}
public static ASingleton getInstance(){
if(instance==null){
synchronized (mutex){
if(instance==null) instance= new ASingleton();
}
}
return instance;
}
}
注意,
String
对象非常不适合来作为同步的锁,因为String
可能是复用的对象,锁定String很容易产生死锁切很难发现,所以这里使用的是Object
对象来作为同步锁。
Java线程和多线程(五)——单例类中的线程安全的更多相关文章
- c++:自己动手实现线程安全的c++单例类
前段时间使用c++做项目开发,需要根据根据配置文件路径加载全局配置文件,并对外提供唯一访问点.面对这样一个需求,自然的就想到了使用单例模式来创建一个单例配置对象,供外部调用.一开始想使用boost中自 ...
- java设计模式--解决单例设计模式中懒汉式线程安全问题
首先写个单例,懒汉模式: public class SingleDemo { private static SingleDemo s = null; private SingleDemo(){} pu ...
- C# 语法五 单例类、单例模式
1.优点 只有一个实例 2.缺点 a)这个实例不能随时释放掉,占用资源. b)每次使用,都要判断是否为空,增加消耗 3.适用场景 只能有一个实例的业务场景,例如:数据库连接对象(每次连接都是同一个连接 ...
- iOS中编写单例类的心得
单例 1.认识过的单例类有哪些: NSUserDefaults.NSNotificationCenter.NSFileManager.UIApplication 2.单例类 单例类某个类在代码编写时使 ...
- 单例类singleton自动释放
body, table{font-family: 微软雅黑; font-size: 10pt} table{border-collapse: collapse; border: solid gray; ...
- [转]单例模式——C++实现自动释放单例类的实例
[转]单例模式——C++实现自动释放单例类的实例 http://www.cnblogs.com/wxxweb/archive/2011/04/15/2017088.html http://blog.s ...
- [iOS]封装单例类
[iOS]封装单例类 今天在学习iOS的SQLite开发,发现在需要使用SQLite的每个视图中,都需要对数据库进行打开或关闭,觉得挺麻烦的:于是在想能否写个单例类对这些操作进行封(因以前一直在使用D ...
- JAVA之旅(十四)——静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制
JAVA之旅(十四)--静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制 JAVA之旅,一路有你,加油! 一.静态同步函数的锁是clas ...
- Java 多线程之单例设计模式
转载:https://segmentfault.com/a/1190000007504892 概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍两种:懒汉式单例.饿汉 ...
随机推荐
- 安装Android模拟器Genymotion【Android学习入门】
安装Android模拟器Genymotion 推荐教程:一个强大的Android模拟器Genymotion具体内容如下: 相信很多Android开发者一定受够了速度慢.体验差效率及其地下的官方模拟器了 ...
- 有趣的回文数(Palindrome number)
文章转自http://blog.163.com/hljmdjlln@126/blog/static/5473620620120412525181/ 做LC上的题"Palindrome num ...
- 如何使用ABAP代码反序列化JSON字符串成ABAP结构
假设我有这个JSON字符串如下图所示: 我的任务是解析出上图黑色方框里的几个字段,比如ObjectID, ETag, BuyerID, DateTime, ID, Name等等,把它们的值存储到对应A ...
- hdu-2844&&POJ-1742 Coins---多重背包
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2844 题目大意: Tony想要买一个东西,他只有n中硬币每种硬币的面值为a[i]每种硬币的数量为c[ ...
- Delphi7 企业版安装记录
Borland Delphi Enterprise Version 7.0[Build 4.453] 云盘下载: 链接:http://pan.baidu.com/s/1gff6Fuz 密码:z ...
- 尝试将 SCRIPT ompbox\private\ompmex 作为函数执行
1.安装VS2010 2.配置ombox 在ombox路径下 mex -setup C++ 然后 make
- Ubuntu搜狗输入法无法输入中文等问题
Linux版本的搜狗输入法经常崩溃,无法输入中文,今天作下记录,环境:Ubuntu14.04 64位 1.安装和卸载 Linux搜狗是基于框架fcitx的,先得安装框架Ubunt安装搜狗方法 也可以直 ...
- RandomUserAgentMiddleware练习
# 请求头添加随机user-agent class RandomUserAgentMiddleware(object): def __init__(self, agents): self.agent ...
- mybatis-generator的maven插件使用异常(mybatis-generator-maven-plugin):generate failed: Exception getting JDBC Driver
使用mybatis的代码生成工具:mybatis-generator,在父model中引入了maven插件的依赖,如下: <!-- Mybatis.generator插件 --> < ...
- HTML5<fieldset>标签
1.<fieldset>标签对表单中的相关元素进行分组. 2.<fieldset>标签会在相关表单元素周围绘制边框. <!DOCTYPE html><html ...