Show Me The Difference (From Alibaba)
公众号:小成同学在coding
文章如有问题欢迎指正
指出以下两段程序的差别,并分析
package com.mashibing.juc.c_35_QuestionsOfAlibaba;
public class ShowMeTheDifference {}
// 4.指出以下两段程序的差别,并分析
final class Accumulator {
private double result = 0.0D;
public void addAll( double[] values) {
for(double value : values) {
result += value;
}
}
}
final class Accumulator2 {
private double result = 0.0D;
public void addAll( double[] values) {
double sum = 0.0D;
for(double value : values) {
sum += value;
}
result += sum;
}
}
这两个程序都不能叫做线程安全。
第一种写法会暴露更多的中间值。
假如我们的double[] values
数组里存放了3个数,在执行这个语句result += value
时,当我们加到任何一个值的时候,在多线程的情况下,我们就能访问到result
这个中间值;比如说,A线程
用Accumulator
这个类来做计算,B线程
也用Accumulator
这个类来做计算,如果多线程访问的是同一个对象的话,中间这个result
值,第一个线程所涉及到的,加了一次数组中的值,很容易就会被第二个线程读取到,如果有三个数,那么0.0D
这个初始值在得到最终结果之前,会变化三次。
第二种写法只会暴露一次最终的result
值,因为它是将数组中的数全加完后,再赋值给result
,如果A线程
和B线程
同时访问,那么B线程
最多只能读取到最后的值,读取不到变化的中间值。
答案: 第二种写法比第一种写法出现不一致性的概率要小,因为我们在方法完成之前,读不到中间状态的
脏数据
尽量少暴露线程计算过程的中间状态
能用范围小的变量,不用范围大的变量