示例代码
@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
时答案 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();
}
}