Java spring多线程原子问题

时间:2015-04-21 13:40:45

标签: java multithreading spring

我有一个班级

@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,但是对该状态的访问由原子变量控制。这个类是否是线程安全的?如果没有,为什么。感谢

2 个答案:

答案 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是线程安全的,因此这将是线程安全的。