我有一个班级
@Component
public class JmxConf implements Serializable {
private static final long serialVersionUID = 5586922486161726170L;
private AtomicInteger count = new AtomicInteger(0);
public AtomicInteger getCount() {
return count;
}
}
我将这个课程自动发送到另一个
@Component
public class QueueListener {
private ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
@Autowired
private JmxConf jmxConf;
public doIt(){
if(jmxConf.getCount().get()>.....) {
jmxConf.getCount().incrementAndget();
......
executor.submit(new thread here);
jmxConf.getCount().decrementAndget();
}
}
}
我们有一个具有状态的单例bean,但是对该状态的访问由原子变量控制。这个类是否是线程安全的?如果没有,为什么。感谢
答案 0 :(得分:4)
不,它不是原子的。你有一场比赛:
if(jmxConf.getCount().get()>.....) {
jmxConf.getCount().incrementAndget();
想象一下greater than
是某个数字的场景,只说10。
if(jmxConf.getCount().get() > 10) {
jmxConf.getCount().incrementAndget();
如果线程点击if
时该值为 9 ,该怎么办?当它达到增量时,它已经被另一个线程增加到 10 ,现在你将它增加到 11 的值。
您应该使用compareAndSet。
while(true){
int value = jmxConf.getCount().get() + 1;
if(value > 10){
break;
}
if(mxConfg.getCount().compareAndSet(value-1, value){
executor.submit(new thread here);
jmxConf.getCount().decrementAndGet();
break;
}
}
您可以阅读有关Java提供的原子引用和compareAndSet
的更多信息。
那么为什么我们需要while(true)
? compareAndSet函数takes two parameters
public final boolean compareAndSet(int expect, int update)
该方法说"尝试在线程安全的事情中更新AtomicInteger,这是我期望它当前的值,这里是我想用它更新它的值。如果,在尝试进行更新时,AtomicInteger的值是我所期望的,而不是您可以安全地进行更新。如果它不是我期望的那样,那就不要更新它并通知我你没有更新它。"
如果另一个线程也尝试使用值 5 if,值为 5 >两个线程都将期望 5 作为参数。因为它是线程安全的,所以只有一个线程可以获胜,这意味着一个线程将失败(compareAndSet将在失败时返回false)。在这种情况下,我们应该重新尝试compareAndSet,直到我们成功或超过我们break
的阈值。
答案 1 :(得分:-4)
AtomicInteger是线程安全的,因此这将是线程安全的。