java - volatile 关键字如何确保对象的字段对其他线程可见?

标签 java concurrency volatile

public class ObjectPropertiesVolatileTest {

    static Cup cup = new Cup();

    public static void changeColor() {
        cup.setColor("black"); // change color of cup to black
    }

    public static void main(String[] args) {
        cup.setColor("red"); // initialize color of cup as red

        for(int i = 0; i < 3; i++) {
            new Thread(){
                public void run() {
                    for(int i = 0; i < 10; i++) 
                        System.out.println(Thread.currentThread().getName()
                                + " " + i + " is " + cup.getColor());

                    if(Thread.currentThread().getName().equals("Thread-1"))
                        changeColor(); // Thread-1 changes the color of cup

                    for(int i = 0; i < 10; i++) 
                        System.out.println(Thread.currentThread().getName()
                                + " " +i + " is " + cup.getColor());

                }
            }.start();
        }

    }

}

class Cup {

    private volatile String color;

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

我的问题是:如何保证对象 cup 的字段 color 仅使用 volatile 关键字而不是使用同步或锁对其他线程可见?

最佳答案

我相信它工作正常。问题是 System.out.println(Thread.currentThread().getName() + ""+i + "is "+ cup.getColor()) 中的打印、打印语句调用、字符串合并;等不同步。

我向您的 getter/setter 添加了打印语句以记录调用时间:-

public String getColor() {
    System.out.println("-------------------------get " + Thread.currentThread().getName() + this.color + " " + System.nanoTime());
    return color;
}

public void setColor(String color) {
    System.out.println("-------------------------set " + Thread.currentThread().getName() + color + this.color + " " + System.nanoTime());
    this.color = color;
}

它打印的片段:-

.
.
.
Thread-0 4 is red
-------------------------get Thread-1red 1356826035808750
Thread-1 8 is red
-------------------------get Thread-2red 1356826035425706
Thread-2 2 is red
-------------------------get Thread-1red 1356826035963697
Thread-1 9 is red
-------------------------get Thread-0red 1356826035894581
-------------------------set Thread-1blackred 1356826036165653
-------------------------get Thread-2red 1356826036036858
Thread-2 3 is black
-------------------------get Thread-1black 1356826036219728
Thread-1 0 is black
Thread-0 5 is red
-------------------------get Thread-1black 1356826036402925
Thread-1 1 is black
-------------------------get Thread-2black 1356826036305139
Thread-2 4 is black
-------------------------get Thread-1black 1356826036535236
Thread-1 2 is black
.
.
.

您关心的问题是这一行:- Thread-0 5 是红色的 它应该打印black,对吧?

好吧,这个线程在另一个线程更改值之前进入了 getter。从这些行可以看出这一点:-

-------------------------get Thread-0red 1356826035894581
-------------------------set Thread-1blackred 1356826036165653

因此它正确读取了值,但与其他线程执行它们正在执行的操作所花费的时间相比,此后完成的处理花费了很长时间。

如果我错了,很高兴有人纠正我。 :)

关于java - volatile 关键字如何确保对象的字段对其他线程可见?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52470335/

相关文章:

java - 使用 XStream 1.4.2 反序列化 transient 字段

java - 无法从 RecyclerView 适配器类调用方法

java - 使用 FutureTask 实现并发

java: volatile数组发布数据变化

c++ - C++ 标准中 7.1.6.1/1 中的这条语句有什么相关性?

java - 在用户定义的 Java 类中创建 ArrayList

java - 什么时候以及为什么我们必须实现 Comparable 接口(interface)?

java - Spark 中的 volatile 变量

java - 如何使用Java同时发送不同的Web服务请求到不同的目的地?

c++ - 从 concurrent_unordered_map 中删除项目列表