使用Atomic Integer时的竞争状况

时间:2019-06-15 21:18:33

标签: java multithreading atomic

我正在学习java.util.concurrent.atomic软件包,并尝试使用Atomic Integer。根据我的理解,Atomic软件包有助于编写无锁代码,而不是使用同步块。因此,为了测试我的理解,我编写了以下代码:

public class Test{

   private final AtomicInteger ai; 

   public void increment() {
        int oldVal = ai.get();

        while(!ai.compareAndSet(oldVal, oldVal+1)) {
            oldVal = ai.get();
        }
    }

    public int incrementModified() {
        return ai.incrementAndGet();
    }

    public int get() {
        return ai.get();
    }

public static void main(String[] args) {
        Test pc = new Test(5);

        Runnable r1 = () -> {
            pc.increment();
        };

        Runnable r2 = () -> {
            pc.increment();
        };

        Runnable r3 = () -> {
            pc.increment();
        };

        Thread t1 = new Thread(r1);

        Thread t2 = new Thread(r2);

        Thread t3 = new Thread(r3);

        t1.start();
        t2.start();
        t3.start();

        System.out.println(pc.get());

    }

当我执行上面的代码时,我希望输出为 8 ,但是我得到的输出为 7/8 。然后,我什至使用了内置的incrementAndGet()方法,并且多次运行该程序后仍然得到相同的输出。

根据我的理解,因为原子可以用作同步块的替代方法,并且通过使用CAS(比较和设置指令)使增量操作成为原子,所以我应该始终将输出设为8。

但是由于我得到的输出不同,所以我假设存在一场比赛,因此o / p在7/8之间变化。

有人可以指出我在上述代码中犯的错误,还是可以纠正我对Java原子类的理解?

编辑:

正如注释中所指出的,我没有使用join(),因此由于主线程正在请求该值而某些线程可能仍在操作中间,因此得到的结果不正确。我添加了它,并对其进行了多次测试,然后可以看到预期的结果。

1 个答案:

答案 0 :(得分:2)

输出值的行与其他3个线程并发执行。如果要确保它在3个线程运行之后执行,则需要在这些线程上加入join()。