原子指令:IF 和循环

Atomic Instructions: IFs and Loops

并发编程中的 IF 语句和循环(如 while 或 do while 原子指令)是原子指令吗?

如果没有,有没有办法自动实现它们?

编辑:修正了我的一些狡猾的英语。

这些可以有任意大且复杂(即非原子)的布尔表达式需要被评估。防止涉及它们的竞争条件的一种方法(如果那是你所说的 "appease" 的意思)是使用某种锁定机制。

在Java中,唯一不需要任何额外工作的原子就是赋值。其他任何东西都需要同步,通过声明方法 synchronized 或使用 synchronized 块。您还可以使用 java.concurrent 中的 类 - 其中一些使用一些更聪明的机制来确保同步,而不是仅仅声明方法 synchronized 往往很慢。


关于 if 语句和您在关于比较的评论中提出的问题 n == m

比较不是原子的。 n 的第一个值必须被加载(这里 m 的值仍然可以改变),然后 m 的值必须被加载,然后计算实际的比较(此时nm 的实际值可能已经与比较中的不同。

如果你想让它同步,你必须这样做:

public class Test {

    private static final Object lock = new Object();

    public static void main(String[] args) {
        if (equals(1, 2)) {
            // do something (not synchronised)
        }
    }

    public static boolean equals(int n, int m) {
        synchronized (lock) {
            return n == m;
        }
    }

}

然而,这提出了一个问题为什么要这样做以及锁应该是什么(以及锁与哪些线程共享)?我想了解有关您的问题的更多背景信息,因为目前我看不出有任何理由做这样的事情。


你还应该记住:

  • 你不能锁定基元(你必须将两个值都声明为 Integer
  • 锁定 null 将导致 NullPointerException
  • 锁是在值上获取的,而不是在引用上。因为 Java 中的整数是不可变的,所以向字段分配新值将导致创建新锁,请参见下面的代码。线程 t1 获取 new Integer(1) 上的锁,而 t2 获取 new Integer(2) 上的锁。因此,即使两个线程都锁定 n,它们仍然可以并行处理。
public class Test {

    private static Integer n = 1;

    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            synchronized (n) {
                System.out.println("thread 1 started");
                sleep(2000);
                System.out.println("thread 1 finished");
            }
        });
        Thread t2 = new Thread(() -> {
            synchronized (n) {
                System.out.println("thread 2 started");
                sleep(2000);
                System.out.println("thread 2 finished");
            }
        });

        t1.start();
        sleep(1000);
        n = 2;
        t2.start();

        t1.join();
        t2.join();
    }

    private static void sleep(int millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

}

您是否考虑过使用可变 AtomicInteger