在看《Java并发编程实战》一书的40页和41页时产生了一个疑问,作者说采用了不可变对象会使这个程序保持线程安全,但是我想了一下发现点问题。
源代码我就懒得打出来了,照两张相吧
现在假如有两个线程A和B,A线程先进行,当A线程访问到
cache = new OneValueCache(i, factors);
然后进入OneValueCache的构造函数,假如线程A在下面代码的第一句后中断了,像下面那样(故意插入一个sleep()让它中断)。
lastNumber = i;
Thread.sleep(1000);
lastFactors = Arrays.copyOf(factors, factors.length);
此时的成员变量cache已经被线程A更改成了一个半初始化的新变量(lastNumber已经被初始化值,但是lastFactors还没初始化,值为初始值null)<这句话是错的,下面分析>。
这时线程B获取cpu执行权,然后访问service()函数,当线程B访问到
BigInteger[] factors = cache.getFactors(i);
此时线程B访问了一个半初始化的成员变量cache,不会产生错误?
这个问题我想了很久,写了很多demo测试,最后发现是我想错了,线程B执行的是原来的cache,cache的值并没有被线程A修改,因为要等到构造函数彻底完成后才会返回this引用,成员变量cache才会更新,所以不用考虑构造函数里面赋值的原子性。