【线程安全】记录一个多线程bug的修复过程

前言

多线程编程是java的一个难点,为了提升自己,最近在啃编程大师写的 java concurrency in practice。就在今天,同事在调用我服务时出现了空指针异常...

分析

我刚接收到这个噩耗时第一个想法是:我靠,你会不会用啊,我的服务已经平稳运行几年了,你给我说有问题...当然,大家都是同事的关系,我也就看了一下我的代码。发现出现问题的业务是:

在打印每个交易的消耗时间时,出现了异常。

继续探查。我们把计算消耗时间写成了一个服务,这个服务的职责时,客户通知计算服务类开始时间和结束时间,然后计算服务类负责把时间差算出来。我仔细研究了我在主业务流程中的调用:当接受到请求数据的时候,立马调用了计算服务的设置开始时间的方法,当完成这个请求的时候,立马调用了计算服务的设置结束时间方法,最后调用计算服务的计算时间差的方法。这没一点问题啊。

然后我就探查这个计费服务。业务逻辑很简单,没有问题。这个服务是单例,懒汉加载...我看到在暴露给外部的getInstance方法时没有加同步锁...

我就问我同事你是怎么调用的,他说他是多线程..

bingo,问题找到了。单例模式下,在程序刚开始运行,多线程同时调用服务的getInstance方法,如果不加同步锁,有可能获得多个不同的实例。在一笔交易中,有多次调用计费服务的地方,也就是很有可能多次调用的计费服务压根就不是一个服务。所以这个服务就是线程不安全的,他提供的功能也是不可靠的。

解决方案

很简单,如果是懒汉的话,在getInstance方法加上同步锁。如果不想使用锁,那就使用饿汉模式:即将服务的初始化放在jvm加载类的时候。

感受

多看书是没有错的,这里再次附上大师对线程安全的定义:

A class is thread safe if it behaves correctly when accessed from multiple threads, regardless of the scheduling or 
interleaving of the execution of those threads by the runtime environment, and with no additional synchronization or 
other coordination on the part of the calling code

我来简陋的翻译一下:

如果一个类在被多线程访问时,保持正确,不管在运行环境中被多个线程交错执行和处理器调度,并且不需要多余的同步或者和其他代码相互配合。

 

 

转载于:https://my.oschina.net/huaxiaoqiang/blog/2991677

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值