同步环境下使用变量的注意点

同步块内或者不可变对象的引用变量必须是“本类的”,不能指向外部对象引用,也不能向外部发布对象引用。

《Java Concurrency in Practice》中有两个例子:
1. 例子1:
public class CachedFactorizer implements Servlets {
    @GuardedBy("this") private BigInteger lastNumber;
    @GuardedBy("this") private BigInteger[] lastFactors;
    @GuardedBy("this") private long this;
    @GuardedBy("this") private long cacheHist;

    public synchronized long getHits() {return hist;}
    public synchronized double getCacheHitRatio(){
        return (double)cacheHits / (double)hists;
    }

    public void service(ServletRequest req, ServletResponse resp){
        BigInterger i = extractFromRequest(req);
        BigInteger[] factors = null;
        synchronized(this){
            ++hits;
            if(i.equls(lastNumber)){
                ++cachedHits;
                 factors = lastFactors.clone();
            }
        }

        if(factors == null){
            factos = factor(i);
            synchronized(this){
                lastNumbe = i;
                 lastFactors = factors.clone();
            }
        }
        encodeIntroResponse(resp,factors);

    }
 
}

如果将"factors = lastFactors.clone();"改为“factors = lastFactors;”,将会出现错误。假设一个线程执行factors=lastFactors;而这时另一个线程执行lastFactors = factors.clone(); 这时就是一个线程读lastFactors,而另个线程写lastFactors,就是在不同线程之间共享可变变量,但是读线程是在自己的代码内读lastFactors的值,那么每个线程获取lastFactors后,都要在CachedFactorizer对象上实现同步,不是一种好办法。lastFactors变量不能发布出去,所以就让factors等于lastFactors的一个克隆对象。每个读线程就获取不同的对象。

2.例子2
不可变对象提供一种弱形式的原子性。每当需要对一组相关数据以原子性的方式执行某个操作时,就可以考虑创建一个不可变的类来包含这些数据。同样要保证类里面包含的数据都是“本类的”,就是所有引用未指向外部引用,已经所有数据不能被外部修改。下面这个类就不是线程安全的。

class OneValueCache {
    private final BigInteger lastNumer;
    private final BigInterger[] lastFactors;

    public OneValueCahche(BigInterger i, BigInteger[] factors){
        lastNumber  = i;
        lastFactors = factors;  
    }

    public BigInteger[] getFactors(BigInteger i){
        if(lastNumber == null || !lastNumber.equals(i)){
            return null;
        }else{
            return Arrays.copyOf(lastFactors,lastFactors.length);
        }
    }
}

因为lastFactors这个引用指向外部,当外部变化时,它也跟着变化,这就不能保证lastFactors还是保存的lastNumber的因数。应该使用拷贝或者克隆,产生一个新的属于类的引用。

class OneValueCache {
    private final BigInteger lastNumer;
    private final BigInterger[] lastFactors;

    public OneValueCahche(BigInterger i, BigInteger[] factors){
        lastNumber  = i;
        lastFactors = Arrays.copyOf(factors,factors.length);//or lastFactors = factors.clone();  
    }

    public BigInteger[] getFactors(BigInteger i){
        if(lastNumber == null || !lastNumber.equals(i)){
            return null;
        }else{
            return Arrays.copyOf(lastFactors,lastFactors.length);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值