Java编程思想SynchronizationComparisons数组越界的问题

    技术2025-04-21  11

    这个Demo有2个地方可能造成数组越界

    (1)BaseLine本身中的index++是线程不安全的

    class BaseLine extends Accumulator {   { id = "BaseLine"; }   @Override public void accumulate() {     value += preLoaded[index++];     if(index >= SIZE) index = 0;   }   @Override public long read() { return value; } }

    解决办法 :

    preLoaded[(index++)%SIZE];

    (2)index.getAndIncrement()和index.set(0)没有同步

    首先index.getAndIncrement()是线程安全的 , i+1也没什么问题 , 但是index.getAndIncrement()和index.set(0)不是同步的

    class AtomicTest extends Accumulator { { id = "Atomic"; } private AtomicInteger index = new AtomicInteger(0); private AtomicLong value = new AtomicLong(0); @Override public void accumulate() { // Oops! Relying on more than one Atomic at // a time doesn't work. But it still gives us // a performance indicator: int i = index.getAndIncrement(); value.getAndAdd(preLoaded[i]); if(i+1 >= SIZE){//有可能一个线程还没设置index.set(0),另一个线程就执行了index.getAndIncrement(),造成数组越界 index.set(0); } } @Override public long read() { return value.get(); } }

    有2种解决办法

    第1种 : 加上synchronized (不过这样做使用AtomicInteger 在accumulate()方法中就没什么意义了 , 普通的int类型也能同步 , 如果你运行的话 , 会发些比单纯使用int和synchronized快很多 , 因为AtomicInteger减少了读取的时间)

    public void accumulate() { synchronized (this) { int i = index.getAndIncrement(); value.getAndAdd(preLoaded[index.getAndIncrement()]); if(i+1 >= SIZE-1){ index.set(0); } } }

    第2种 : 保证测试的次数不超过数组的大小(这样就不用设置index.set(0)了)

    public void accumulate() { int i = index.getAndIncrement(); value.getAndAdd(preLoaded[i]); }

     

    Processed: 0.009, SQL: 9