【问题标题】:Atomic Instructions: IFs and Loops原子指令:IF 和循环
【发布时间】:2015-10-31 19:20:35
【问题描述】:

IF 语句和循环,例如 while 或 do while 原子指令在并发编程中吗?

如果没有,有没有办法以原子方式实现它们?

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

【问题讨论】:

  • “安抚”并发线程是什么意思?
  • 已编辑以修复它。我的意思是,有没有一种方法可以将实际语句(IF 或循环)算作原子指令。
  • 在任何现代平台上都存在的最强大的原子操作是比较和交换(CAS)。你可以自己google它的算法。为了实现更复杂操作序列的原子性,您需要使用额外的同步机制,例如锁。

标签: loops if-statement concurrency atomic


【解决方案1】:

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


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

比较不是原子的。必须加载n 的第一个值(这里m 的值仍然可以更改),然后必须加载m 的值,然后评估实际比较(此时两个@ 的实际值987654329@ 和 m 可能已经与比较中的不同)。

如果您希望它同步,您必须执行以下操作:

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 如果被评估的表达式只是比较两个整数呢?如果(n==m)而(n==v){}
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-23
    • 2014-11-09
    • 2014-04-09
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多