Java 中的原子是保证顺序还是仅保证唯一性?

Do atomics in Java guarantee ordering or only uniqueness?

在执行以下代码片段时,我看到结果正在正确且唯一地递增,但是它们打印的顺序是乱序的(如下所示):

 import java.util.concurrent.atomic.AtomicInteger;

public class Atomics {

    private AtomicInteger index = new AtomicInteger(0);

    public static void main(String [] args) {
        new Atomics().updateIndexViaCAS();
    }

    private  void updateIndexViaCAS() {

        Runnable target = () -> {
            for(int i = 0; i<10;i++) {
                cas:
                while (true) {
                    int oldValue = index.get();
                    int newValue = oldValue + 1;
                    if(index.compareAndSet(oldValue, newValue)) {
                        System.out.println(Thread.currentThread() + ": "+newValue); //order is not guaranteed?
                        break cas;
                    }
                }
            }
        };

        /*Runnable target = () -> {
            for (int i = 0; i < 10; i++) {
                int oldValue = index.get();
                int newValue = oldValue + 1;
                do {
                    oldValue = index.get();
                } while (!index.compareAndSet(oldValue, newValue));
                System.out.println(Thread.currentThread() + ": "+newValue);
            }
        };*/

        for(int t=0; t<2;t++) {
            Thread th = new Thread(target);
            th.start();
        }


    }
}

示例结果:

Thread[Thread-0,5,main]: 1
Thread[Thread-0,5,main]: 3
Thread[Thread-0,5,main]: 4
Thread[Thread-0,5,main]: 5
Thread[Thread-0,5,main]: 6
Thread[Thread-1,5,main]: 2 <-- out of order
Thread[Thread-0,5,main]: 7
Thread[Thread-0,5,main]: 9
Thread[Thread-0,5,main]: 10
Thread[Thread-0,5,main]: 11
Thread[Thread-0,5,main]: 12
Thread[Thread-1,5,main]: 8  <-- out of order
Thread[Thread-1,5,main]: 13
Thread[Thread-1,5,main]: 14
Thread[Thread-1,5,main]: 15
Thread[Thread-1,5,main]: 16
Thread[Thread-1,5,main]: 17
Thread[Thread-1,5,main]: 18
Thread[Thread-1,5,main]: 19
Thread[Thread-1,5,main]: 20

是否因为:

  1. 代码有问题(如果有,如何修复它以强制执行排序)?

  2. 这是原子的正确行为吗,因为在设计上它们不保证执行顺序而只保证无锁并发?

  3. 这里还有其他工作吗?

TIA。

为了解决我对下面评论的困惑 - 如果我仍然需要使用同步来查看下面发生的事情,为什么我首先需要 Atomics?

Runnable target = () -> {
    for (int i = 0; i < 10; i++) {
        cas: while (true) {
            synchronized (mutex) {
                int oldValue = index.get();
                int newValue = oldValue + 1;
                if (index.compareAndSet(oldValue, newValue)) {
                    System.out.println(Thread.currentThread() + ": "
                            + newValue); // order is not guaranteed?
                    break cas;
                }
            }
        }
    }
};

无法保证您的代码如何交错。在您的情况下,我认为令人困惑的是循环不是作为一个单元执行的,而是可以以任何方式交错。想想线程 1 在执行 System.out.println(Thread.currentThread() + ": " + newValue) 之前停止,其中 newValue0 递增到 1 所以还没有打印任何东西。然后线程 2 可以从 1 增加到 2 并在另一个线程之前打印它的输出。这将导致先打印较大的数字。

此外,请记住 System.out.printlnSystem.out 上同步。这就是为什么您总是以正确的顺序观察大块印刷品的原因。一个线程可能发现 System.out 已锁定并在恢复其 activity.

之前暂停其 activity 一小会儿