单例模式是最广泛使用的创建模式之一。在现实世界之中,诸如Databae的连接或者是企业信息系统(EIS)等,通常其创建都是受到限制的,应该尽量复用已存在对象而不是频繁创建销毁。为了达到这个目的,开发者通常会通过实现单例模式来创建一个wrapper类,来封装资源,限制其运行时所创建对象的个数。

单例中的线程安全

总的来说,开发者一般会按照如下的方式来创建单例的类:

  1. 使用私有构造函数来避免其它外部引用通过new的方式来创建新的对象引用。
  2. 声明一个该类的私有静态变量为实例。
  3. 提供一个公有的静态方法来返回单例的实例。如果实例还没有初始化的话,就将其初始化后再返回实例。

通过上面的步骤,我写了一个如下的单例类:

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线程和多线程(五)——单例类中的线程安全的更多相关文章

  1. c++:自己动手实现线程安全的c++单例类

    前段时间使用c++做项目开发,需要根据根据配置文件路径加载全局配置文件,并对外提供唯一访问点.面对这样一个需求,自然的就想到了使用单例模式来创建一个单例配置对象,供外部调用.一开始想使用boost中自 ...

  2. java设计模式--解决单例设计模式中懒汉式线程安全问题

    首先写个单例,懒汉模式: public class SingleDemo { private static SingleDemo s = null; private SingleDemo(){} pu ...

  3. C# 语法五 单例类、单例模式

    1.优点 只有一个实例 2.缺点 a)这个实例不能随时释放掉,占用资源. b)每次使用,都要判断是否为空,增加消耗 3.适用场景 只能有一个实例的业务场景,例如:数据库连接对象(每次连接都是同一个连接 ...

  4. iOS中编写单例类的心得

    单例 1.认识过的单例类有哪些: NSUserDefaults.NSNotificationCenter.NSFileManager.UIApplication 2.单例类 单例类某个类在代码编写时使 ...

  5. 单例类singleton自动释放

    body, table{font-family: 微软雅黑; font-size: 10pt} table{border-collapse: collapse; border: solid gray; ...

  6. [转]单例模式——C++实现自动释放单例类的实例

    [转]单例模式——C++实现自动释放单例类的实例 http://www.cnblogs.com/wxxweb/archive/2011/04/15/2017088.html http://blog.s ...

  7. [iOS]封装单例类

    [iOS]封装单例类 今天在学习iOS的SQLite开发,发现在需要使用SQLite的每个视图中,都需要对数据库进行打开或关闭,觉得挺麻烦的:于是在想能否写个单例类对这些操作进行封(因以前一直在使用D ...

  8. JAVA之旅(十四)——静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制

    JAVA之旅(十四)--静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制 JAVA之旅,一路有你,加油! 一.静态同步函数的锁是clas ...

  9. Java 多线程之单例设计模式

    转载:https://segmentfault.com/a/1190000007504892 概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍两种:懒汉式单例.饿汉 ...

随机推荐

  1. MySQL的基础(优化)1

    1,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设得尽可能小 2,在可能的情况下,应该尽量把字段设置为NOT NULL,这样在将来执行查询的时候,数据库不用去比较NULL值 3,对于某 ...

  2. Linux 使用第三方邮箱发邮件的设置

    mail命令在Ubuntu下是需要安装的,使用下条命令进行安装: sudo apt-get install heirloom-mailx 在CentOS 下安装则是: yum install mail ...

  3. InnoDB多版本(MVCC)实现简要分析

    转载自:http://hedengcheng.com/?p=148 基本知识 假设对于多版本(MVCC)的基础知识,有所了解.InnoDB为了实现多版本的一致读,采用的是基于回滚段的协议. 行结构 I ...

  4. MySQL latch小结

      lock和latch的比较 对于INNODB存储引擎中的latch可以通过命令 SHOW ENGINE INNODB MUTEX 看到latch的更多信息 说明: 列Type显示的总是 InnoD ...

  5. 获取url中的某个字段的值

    function getUrl(name, url) { url = url || window.location.search; var reg = new RegExp("(^|& ...

  6. java中string类型转换成map

    背景:有时候string类型的数据取出来是个很标准的key.value形式,通过Gson的可以直接转成map 使用方式: Gson gson = new Gson(); Map<String, ...

  7. POJ-2029 Get Many Persimmon Trees---二维树状数组+枚举

    题目链接: https://vjudge.net/problem/POJ-2029 题目大意: 有N棵树在一个n*m的田里,给出每颗树的坐标 用一个s*t的矩形去围,最多能围几棵树 思路: 用二维树状 ...

  8. jade文档声明和头尾标签

    作为一个页面,首先需要一个doctype的声明,它位于文档最上面的位置,放置html标签以前,用来告知浏览器当前这个页面用哪种html,或者xml的规范并解析页面   doctype html htm ...

  9. Linux空间PHP开发环境小白教程(LAMP)

    租了一个云服务器, 但是只有linux系统,没有php开发环境, 只好自己摸索着一步一步安装啦. 本教程来自自学IT创E老师的Linux教程,想详细了解的可以去论坛找. 一.使用PUTTY登录服务器 ...

  10. Python-程序模块化

    一.程序模块化 一个程序可能需要导入自己写的模块,或者需要导入.查找.修改文件等操作.当把程序移植到其他路径执行时,会因为模块或文件路径的变化而报错. 程序模块化,就是将整个程序(包含该程序需要用到的 ...