单例模式是最广泛使用的创建模式之一。在现实世界之中,诸如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. u-boot分析(十一)----MMU简单分析|u-boot分析大结局|学习规划

    u-boot分析(十一) 通过前面十篇博文,我们已经完成了对BL1阶段的分析,通过这些分析相信我们对u-boot已经有了一个比较深入的认识,在BL2阶段大部分是对外设的初始化,并且有的我们已经分析过, ...

  2. SqlServer存储过程中常用函数及操作

    1.case语句 用于选择语句 SELECT ProductNumber, Category = CASE ProductLine WHEN 'R' THEN 'Road' WHEN 'M' THEN ...

  3. 类型信息(RTTI和反射)——反射

    运行时类型信息可以让你在程序运行时发现和使用类型信息. 在Java中运行时识别对象和类的信息有两种方式:传统的RTTI,以及反射.下面就来说说反射. 重点说说通过反射获取方法以及调用方法,即类方法提取 ...

  4. prop & attr

    <input id="chk1" type="checkbox" />是否可见 <input id="chk2" type ...

  5. 笨办法学Python(四)

    习题 4: 变量(variable)和命名 你已经学会了 print 和算术运算.下一步你要学的是“变量”.在编程中,变量只不过是用来指代某个东西的名字.程序员通过使用变量名可以让他们的程序读起来更像 ...

  6. 验证tensorflow版本是GPU还是CPU

    reference: https://blog.csdn.net/zlase/article/details/79261348 import numpy import tensorflow as tf ...

  7. IOS Post请求(请求服务器)

    @interface HMViewController () @property (weak, nonatomic) IBOutlet UITextField *usernameField; @pro ...

  8. java 生成12位随机数,解决The literal 9999999999999 of type int is out of range 问题

    原本想这样产生一个随机数,但是你会看到,只要数字超过了9位数,就会出问题,提示“The literal 1000000000000 of type int is out of range” 解决方式是 ...

  9. POJ-3126 Prime Path---BFS+素数打表

    题目链接: https://vjudge.net/problem/POJ-3126 题目大意: 给两个四位数a,b 每次改变a中的一位而且改动之后的必须是素数,问最少改动几次可以到b?(永远达不到b就 ...

  10. 定位webpack文件大小

    之前发现一个神器,记录一下,可以可视化webpack打包的每个js文件大小,这样对我们优化代码是有帮助的,有目标的 https://www.npmjs.com/package/webpack-bund ...