对Atomic Integer线程安全的条件检查?

时间:2016-04-14 22:02:37

标签: java multithreading atomicity

示例代码

@ApplicationScoped
public class AtomicIntegerSample {

private final AtomicInteger successFullSyncCount = new AtomicInteger(0);
private final AtomicLong overallSyncTimeTaken  = new AtomicLong(0);

public void incrementSuccessFullSyncCount() {
    this.successFullSyncCount.incrementAndGet();
}


public void addOverallSyncTimeTaken(final Long syncTimeTaken) {
    overallSyncTimeTaken.addAndGet(syncTimeTaken);
}
/**
 * Can be called by multiple threads
 * @return
 */
public long getAverageSuccessfulSyncTimeTaken() {
    if (successFullSyncCount.get() == 0) {
        return 0;
    } else {
        return overallSyncTimeTaken.get() / successFullSyncCount.get();
    }
}

在方法getAverageSuccessfulSyncTimeTaken()中,有条件检查以避免算术异常。

ApplicationScoped类,此方法可以由多个线程同时调用。

方法线程安全吗?如果我按如下方式替换代码,它是否是线程安全的?

 /**
 * Can be called by multiple threads
 * @return
 */
public long getAverageSuccessfulSyncTimeTaken() {
       return overallSyncTimeTaken.get() / successFullSyncCount.get();

}

然后抛出算术异常。如何最佳地同步这段代码?我的意思是只有当successFullSyncCount.get()== 0

2 个答案:

答案 0 :(得分:3)

它不会抛出任何异常,但它可能会返回错误的结果:

  • 时间和计数分别递增。它们不会在单个原子操作中同时增加两个
  • 单独读取时间和计数,而不是在单个原子操作中同时读取。

因此,您可以在一个线程中读取100的时间,然后让另一个线程将计数增加几次,然后读取计数并执行除法。因此,这可以导致每个同步的平均时间低于实际值。它可能是一个足够好的近似值,或者不是。

答案 1 :(得分:0)

以下是不使用原子对象的版本。

如果您希望将时间和计数一起更新,则同步块可能更适合。这将阻止您的平均方法被多个关闭。不可否认,同步块比原生原子实现慢,但我不确定优化是否为时过早。

@ApplicationScoped
public class AtomicIntegerSample {

private int successFullSyncCount = 0;
private long overallSyncTimeTaken  = 0;


synchronized public void addSyncTimeTakenAndIncrementSyncCount(final Long syncTimeTaken) {
    overallSyncTimeTaken+=syncTimeTaken;
    successFullSyncCount++;
}
/**
 * Can be called by multiple threads
 * @return
 */
public long getAverageSuccessfulSyncTimeTaken() {
    if (successFullSyncCount.get() == 0) {
        return 0;
    } else {
        return overallSyncTimeTaken.get() / (float) successFullSyncCount.get();
    }
}