我想跟踪在synchronized
块内修改的队列中的位置。因此我需要一个计数器变量。通常情况下我会使用AtomicInteger
,但我在这需要吗?
PriorityBlockingQueue<TfIdfScore> allScores = sharedFeatureNameToScores.get(featureName);
synchronized (allScores) {
AtomicInteger position = positionCounterMap.get(featureName);
position.getAndAdd(1);
// Do other stuff..
}
或者我也可以使用int
或Integer
吗? synchronized
块是否会保护我在块内的所有操作?
在此示例中,position
和allScores
取决于相同的featureName
。
答案 0 :(得分:4)
如果您正在编写所有代码(并采取适当的谨慎),那么您不需要同时使用synchronized
和原子类型。只要确保给定地图上的所有操作及其包含的计数器在同一个对象上同步...并且该部分代码应该是线程安全的。
另一方面,如果您担心有人会忘记同步,那么原子类型可能无法解决问题。更好的解决方案是确保映射和计数器得到很好的封装,以减少错误的范围。 (如果可以减少可以访问状态的代码量,则会减少检查线程安全所需的位置数。)
synchronized块是否保护了我在块内的所有操作?
不一定。
如果其他代码访问或更新数据结构, 代码没有在正确的互斥锁上同步,您仍然可能遇到线程安全问题;例如相同的allScores
实例。
答案 1 :(得分:1)
同步比原子或易失性更严格。因此,您无需在同步
中使用原子同步
同步方法启用了一种简单的策略来防止线程干扰和内存一致性错误:如果一个对象对多个线程可见,则对该对象变量的所有读取或写入都是通过同步方法完成的。
挥发性
volatile字段意味着变量不会被缓存在处理器核心/线程中。因此,每个核心/线程只有一个变量副本
原子
java.util.concurrent.atomic包定义了支持单个变量的原子操作的类。所有类都有get和set方法,类似于对volatile变量的读写操作。也就是说,一个集合与之前的相关变量的任何后续获取具有先发生关系。原子compareAndSet方法也具有这些内存一致性功能,适用于整数原子变量的简单原子算法也是如此。
答案 2 :(得分:1)
在您的代码中,您使用featureName使用两个不同的对象:sharedFeatureNameToScores
和positionCounterMap
。
为了保证您的代码是线程安全的,您需要确保使用相同的锁(代码中为synchronized (allScores)
)对它们进行修改。一旦满足此要求,就不需要使用AtomicInteger,因为synchronized块可以保护两者,因此以独占模式访问positionCounterMap
。