java - id = 1 - id 是原子的吗?

标签 java multithreading atomic swap scjp

来自 OCP Java SE 6 Programmer Practice Exams 的第 291 页,问题 25:

public class Stone implements Runnable {
    static int id = 1;

    public void run() {
        id = 1 - id;
        if (id == 0) 
            pick(); 
        else 
            release();
    }

    private static synchronized void pick() {
        System.out.print("P ");
        System.out.print("Q ");
    }

    private synchronized void release() {
        System.out.print("R ");
        System.out.print("S ");
    }

    public static void main(String[] args) {
        Stone st = new Stone();
        new Thread(st).start();
        new Thread(st).start();
    }
}

答案之一是:

The output could be P Q P Q

我将此答案标记为正确。我的推理:

  1. 我们正在启动两个线程。
  2. 第一个进入run()
  3. 根据JLS 15.26.1 ,它首先评估 1 - id。结果是 0。它存储在线程的堆栈中。我们正要将该 0 保存为静态 id,但是...
  4. Boom,调度程序选择了第二个线程来运行。
  5. 所以,第二个线程进入run()。静态的id还是1,所以他执行方法pick()P Q 被打印出来。
  6. 调度器选择第一个线程来运行。它从堆栈中取出 0 并保存到静态 id。因此,第一个线程也执行 pick() 并打印 P Q

但是,书中写到这个答案是不正确的:

It is incorrect because the line id = 1 - id swaps the value of id between 0 and 1. There is no chance for the same method to be executed twice.

我不同意。我认为我上面介绍的场景有一些机会。这种交换不是原子的。我错了吗?

最佳答案

Am I wrong?

不,你是绝对正确的 - 就像你的示例时间线一样。

除了它不是原子的之外,不保证写入 id 无论如何都会被其他线程拾取,因为没有同步并且该字段不是 volatile 的。

这样的引用资料不正确有点令人不安:(

关于java - id = 1 - id 是原子的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27089196/

相关文章:

java - 错误 : field name cannot be declared static

java - Java中创建硬链接(hard link)和删除文件的原子操作

c++ - future::wait() 是否与 async() 执行线程的完成同步?

c# - 具有内部方法的 Java 公共(public)类

java - Outputstream是一个抽象类,所以我们不能实例化它。为什么要为Outputstream类提供一个默认的构造函数呢?

java - LibGDX 服务器线程

c - 多线程程序中不接收UDP并输出数据

java - 访问动态资源消息

java - 将关联数组(Hashmap)作为参数传递给 xml rpc

c++ - 在 C++11 中将原子与 std::thread 一起使用