美文网首页
并发情况下的单例模式

并发情况下的单例模式

作者: Y_Q | 来源:发表于2017-12-28 14:58 被阅读15次

背景:有多个客户端会同时上传压缩包至平台,压缩包中有多个txt文件,平台会逐一解析然后将他们的数据入库。

但是,在实践中发现,经常会有数据没有写入数据库的现象发生。但是log记录的是平台对其有进行分析的。

那么问题的原因就可以缩小到“数据解析”->"数据入库”的环节。

我的代码中, 数据解析的类是StabilityPerfReportHandler.java,数据入库的类是StabilityPerfReportDao.java

先看一下整体的代码结构

因为有多个文件,如果等到文件解析完再返回客户端一个值,则容易引起返回超时,导致文件重传。所以在Handler中是采用多线程对每个文件进行数据解析及入库的。那么就猜测,数据有解析但是没有写入数据库的原因是多线程同时调用了StabilityPerfReportDao.java中的入库函数,导致有冲突。

那么我的第一个尝试是:给每个写入数据库的函数加锁

原先:

public void insertCpuData(List listCpuResults)

改后:

public synchronized void insertCpuData(List listCpuResults)

事实证明,这种修改是没有作用的。

但是可以肯定的一点就是在写入数据库的时候是存在冲突问题的,导致数据写入的时候,有些数据没写入丢失。

再次梳理了一下代码,发现在解析完数据要写入数据库时采用的是单例的形式

StabilityPerfReportDao.getInstance().insertCpuData(stabilityPerfCPUPos);

查看了StabilityPerfReportDao的单例代码,发现是如下的:

public static StabilityPerfReportDao getInstance() {

        if (null == stabilityPerfReportDao) {

            synchronized (StabilityPerfReportDao.class) {

                if (null == stabilityPerfReportDao) {

                stabilityPerfReportDao = new StabilityPerfReportDao();

                }

            }

        }

       return instance;

    }

查阅了相关资料,发现这段代码在多线程并发的情况下是有问题的。

最根本的原因是,java寄存器的读写是无序的

当我们new一个对象的时候,java是经历以下三个步骤的:

a.给实例分配内存

b.初始化构造器(构造器的作用就是给变量赋值)

c.将引用指向分配的对存

我们的期望是a->b->c,但是由于java寄存器的读写是无序的,所以他可能的顺序是a->c->b。如果顺序是a->c->b,那么我们获得的对象是没有被初始化的,这样就会产生问题。

结合到我们上述有问题的代码来看,就是以下这样的 

a.线程A、B同时调用StabilityPerfReportDao.getInstance()

b.线程B先进入,判断到StabilityPerfReportDao为空,则进入到synchronized模块中,new一个StabilityPerfReportDao对象

c.此时线程A进入,判断到StabilityPerfReportDao不为空,便返回了这个instance,但是这个instance是还没有经过构造器初始化的,所以线程A拿到这个instance去执行接下来的操作会出现问题。

现在问题找到了,就要相处解决的方法了,以下是我解决的代码

private static StabilityPerfReportDao instance = new StabilityPerfReportDao();

public static StabilityPerfReportDao getInstance() {

        return instance;

    }

在类加载的时候,就去定义一个静态变量instance并初始化它。接下来每个外部类调用getInstance去获得唯一备份的instance。代码这么修改之后,就完美地解决了问题了。

相关文章

  • 并行模式与算法

    java高并发程序设计 - 网易云课堂 一、单例模式 高并发情况下的单例模式 public class Stati...

  • 单例模式Java篇

    单例设计模式- 饿汉式 单例设计模式 - 懒汉式 单例设计模式 - 懒汉式 - 多线程并发 单例设计模式 - 懒汉...

  • Swift的单例模式及如何处理并发访问

    Swift的单例模式 Swift有两种方式实现单例模式 1、全局常量 2、类型常量 处理单例模式的并发访问 1、多...

  • 并发情况下的单例模式

    背景:有多个客户端会同时上传压缩包至平台,压缩包中有多个txt文件,平台会逐一解析然后将他们的数据入库。 但是,在...

  • 设计模式——单例模式的破坏

    概述: 之前学习了单例模式的几种实现,解决了多线程情况下,单例的线程安全问题,保证了单例的实现。但是单例模式在下面...

  • 说说spring用了哪些设计模式

    单例模式:Spring 中的 Bean 默认情况下都是单例的。无需多说。工厂模式:工厂模式主要是通过 BeanFa...

  • Javascript Singleton(单例)模式

    单例模式的定义:单例模式,顾名思义,就是只能实例化一次。单例模式的核心思想就是 : 在该实例 不存在 的情况下,可...

  • 创建型-单例模式

    Singleton .java 单例模式Demo 单例模式是指的什么意思? 我们自己定义的类,其实默认情况下,都是...

  • 《我想进大厂》之Spring夺命连环10问

    1.说说Spring 里用到了哪些设计模式? 单例模式:Spring 中的 Bean 默认情况下都是单例的。无需多...

  • Spring 面试题

    1.说说Spring 里用到了哪些设计模式? 单例模式:Spring 中的 Bean 默认情况下都是单例的。无需多...

网友评论

      本文标题:并发情况下的单例模式

      本文链接:https://www.haomeiwen.com/subject/lltpgxtx.html