我们公司一个程序员同事跟我说:“我碰到了一段很诡异的代码!”,听他说的有点神经兮兮的,于是我就好奇什么代码能称之为“诡异”。然后他跟我解释,说他写了一个for循环,然后通过for循环的索引去取数组对应下标的值,但是,这段代码似乎不起效果,并且明明循环终止条件设置的是i<=20,但是最后发现i的值竟然有21!我一听他这么描述事情,立马就来了兴趣。
然后我就拿着他的代码调试了一下,发现真的如他描述的那样,循环终止条件是i<=20,但是i最后的值是21!
代码问题的确很诡异,但是我喜欢!可我看了一会儿他的代码,有点丢脸,我也一时不确定他代码哪里写得有问题!但是,唯一可以确定的是,他的for循环里面使用了异步线程,我估计问题还是出在了线程上。
于是,我自己写了一个demo完全模拟他的写法,来验证我的想法。
我写了一个0到20的for循环,然后直接异步输出i的值,最后我发现,这个i的值不光能输出21,甚至于21次输出有一大半的输出i的值都是21!
思考了片刻,我总结出了问题出现的原因!
之所以出现这个问题,是因为这个循环内部使用了异步输出,在并发输出的情况下i的输出顺序是不确定的,也破坏了i这个值的原子性,最后可能导致在输出的时候i的值与预期不同。
打个简单的比方吧,因为for循环内部使用了异步输出,所以for循环会在极短的时间内执行完成,而在for循环执行完成以后,异步逻辑可能才被执行,此时,i的值可能就是20,因此如果异步输出的逻辑在for循环结束之后被执行,那么此时输出i,那么i的值就应该是20,所以,原则上将会出现大量输出20的值!
但是,我们也发现了,i的值跟我们想的并不一样,它不是20而是21,这就得说到for循环的执行逻辑了。
假设i的起始值是0,结束值是20,for循环的执行逻辑是每循环一次都会给i+1,当准备进入下一次循环的时候,会先判断i是否大于结束值,如果大于则不执行。
也就是说,for循环在执行完最后一次循环的时候,仍然给i+了1,所以,此时如果正好异步输出的逻辑被执行,那么i就等于21!
我们可以用一个简单的例子来证明这个推论(这里没有复杂的编程基础知识,全靠验证)。
我们可以在for循环外面定义一个变量i,值为0,也就是避免在for循环时才创建变量,供我们在for循环外部调用输出,当for循环结束后(这里没有任何异步操作),我们再输出i的值,此时您会发现,i的值是21而不是我们预想中的20!
问题我们都知道了,但是我的同事的for循环里必须使用异步怎么办呢?解决办法也很简单,那就是在每次循环时直接定义一个变量去获取i的值,而这个变量相对于for循环是原子性的,然后,在异步时使用这个变量而不直接使用i,就这样,问题成功解决!
怎么样?您学会了吗?
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.