2

java并发教程指出:

对于引用变量和大多数原始变量(除了 long 和 double 之外的所有类型),读取和写入都是原子的。
对于声明为 volatile 的所有变量(包括 long 和 double 变量),读取和写入都是原子的。

我创建了一个简单的实验来测试这个

package experiment0;

public class Experiment0 {

    public static int i=9;

    public static void main(String[] args) {
        i=9;
        (new Thread(){
            public void run(){
                while(i==9){
                    //System.out.println("i==9");
                }
                System.out.println("\ni!=9");
            }
        }).start();
        (new Thread(){
            public void run(){
                try{
                    Thread.sleep(3000);
                    i=8;
                }catch(Exception e){

                }
            }
        }).start();
    }
}

当我运行此代码时,程序永远不会终止!为了让它工作,我要么取消注释第一个线程的 while 循环内的行,要么声明ivolatile. 我错过了什么吗?文档是否错误,是否应该说在这种情况下所有原语都应声明为易失性?为什么要写System.out“解决”问题?它是否给第二个线程足够的时间来改变i

4

1 回答 1

3

写入是原子的意味着写入作为单个原子操作执行。除了赋值之前或之后的值,没有其他线程可以看到其他内容。

例如,在长值的情况下,赋值不是原子的,因为它实际上是作为两个操作执行的:一个分配前 32 位,另一个分配最后 32 位。因此,另一个线程可能会在仅执行两个操作中的一个之后读取变量的值,因此看到的值既不是前值也不是后值,而是“中间”值。

您的程序演示的是,在没有任何同步的情况下写入变量会导致线程之间的可见性问题。一个线程完成的写入操作对另一个线程不可见。这是由于每个处理器都有自己的缓存,并且在每次分配时都不会写入主存储器。为确保写入可见,您需要使变量为 volatile,或同步对变量的访问,或使用 AtomicInteger。

于 2012-10-21T14:22:48.667 回答