困扰了程序员半个月的Bug,被解决之后,程序员:“就这?”

话说,我们公司有个项目在二十多天前就已经到了合同约定的验收时间了,但是因为项目当时上得比较急,所以,在验收时间到达的时候,我们老板跟客户好说歹说才又争取了一个星期的延期。

当初我认为一个星期的时间是绰绰有余的,并且,我也在规定的时间内完成了我自己所承担的所有开发内容,但是,谁知道一个星期后,这个项目还是没有达到验收标准,原因就是我同事负责的一个功能运行得始终有问题。

简单地说,同事负责开发的这个功能是需要同时向多个机械设备发送指令让其按照规则运转,注意,是同步运转!而问题也出在这里!

同事代码出现问题的特征就是,他写的代码并不是百分百有效,有时候发送指令效果是正确的,即几个机械设备在同时运转,但有时候就只有那么一两个机械设备在运转。

遇到这个问题,我首先想到的就是让同事去调试,看看指令是否正确发到了每个机械设备上了。结果,这半个月,我同事当着我的面调试了好几次,发现指令发的都是对的!

开始,我还没发现问题,后来当问题解决了以后,我回想我每次看同事调试的时候的场景,我才意识到,我同事每次在调试的时候,设备都能正常运转原因!

因为总是解决不掉问题,客户那边也摆烂了,随我们搞,但是却没有给我们好脸色,这让我有点被殃及池鱼的感觉!

后来,直到有一天,我被客户那边一个PM给说了一顿后,情绪有点失控,所以,我就下定决心好好找一找我同事代码中的茬!

因为同事需要操作的机械设备逻辑比较复杂,所以,我看着也有些迷迷糊糊的,所以一时半会儿也找不到问题出在哪!

最后,我决定使用排除法,把同事代码中所有跟问题无关的代码全部注释掉,只留下关键代码的方式去找问题,我不知道这方法有没有用,但我还是决定死马当活马医!

谁知道,就是因为我的这一个操作,找到了导致代码不能正确运行的原因!

因为代码比较复杂,我在注释同事写的跟问题无关的代码的时候,一边问同事一边注释,结果当我瞥到一个字段的时候,我竟然发现这个字段竟然是静态的!

这个字段我其实一直很熟悉,它代表的是需要操作的设备的索引!我脑袋当时就炸了,因为这个静态字段所在的实体类是需要实例化的!我一直没注意,以为它是类的实例字段。

首先,在一个需要实例化的实体类中放一个静态字段本身就不太合适,除非这个静态字段的值是个常量(勉强能解释吧)。

但是,这个静态字段表示的是设备的索引,在实例化后是要被赋值的,因此,静态字段表示设备的索引,显然是有问题的。

这么一想,我突然就豁然开朗了!

示例

示例

前面说了,同事代码的问题点就是每次向设备发送指令的时候,就一两个设备有响应,在调试代码的时候,却又是正常执行的,即所有设备都能响应。

问题恰恰就出在这个静态字段上!

因为,向设备发送指令是使用线程异步发送的,而每次发送指令,都需要实例化一个发送指令的实体,并且给这个实体中的静态字段即表示设备索引的字段赋值。

但是,因为是异步发送的,表示设备索引的那个字段又是静态的,那么完全有可能在发送指令的时候,设备索引又被重新赋了值,从而导致指令没有向正确的设备发送。

比如说,假设给设备索引的这个字段赋值为0,当代码还没执行到发送指令的代码段时,其他线程又给设备索引赋值为了1,而当两个线程都走到了发送指令这块代码时,此时,设备索引这个字段的值也就只能是1了,造成的结果就是索引为0的设备没有收到指令,而索引为1的设备,则收到了两次指令!

而当同一个设备收到相同指令时,新的指令会覆盖旧的指令,因此,从感官上,不会有任何不正常的情况。

这个道理说通了,那么就可以解释问题了,因为在极端情况下,是会出现只有一台设备收到指令的情况,这种情况,代码执行得很快的话,概率是非常高的!

另外,也可以解释为什么有时候只有一两个设备收到了指令,因为只要设备索引这个静态字段值在没被下一个索引的值覆盖前执行了指令代码,那么,相关设备就会收到指令信号!

至于调试的时候,为什么都能执行正确呢?那就更简单了,因为同事在代码中下了断点,阻碍了代码的正常执行,也就会导致设备索引这个字段是按照顺序被赋值和发送指令的,因此就不会出问题!

结语

我叹了一口气,困扰了我们,准确的说困扰了我同事半个月时间的问题,总算是找到了!我也是无语了,就问同事为什么会把设备索引这个字段写成静态的。

结果同事想了半天,也说不出个所以然来!最后我也不想说啥,只要项目能够顺利验收就好!

在解决问题后,我总结了下,同事代码出现问题有很多必然性,我到现在都搞不清楚为什么在一个实体类里面用静态字段,还需要赋值!

最后,半个月啊!就这?