gpt4 book ai didi

java - Java 缓存整个对象还是仅缓存对象的一部分? (可见性问题)

转载 作者:行者123 更新时间:2023-12-02 08:51:09 25 4
gpt4 key购买 nike

我试图故意创建线程的可见性问题,但得到了意想不到的结果:

public class DownloadStatus {
private int totalBytes;
private boolean isDone;

public void increment() {
totalBytes++;
}

public int getTotalBytes() {
return totalBytes;
}

public boolean isDone() {
return isDone;
}

public void done() {
isDone = true;
}
}
public class DownloadFileTask implements Runnable {
DownloadStatus status;

public DownloadFileTask(DownloadStatus status) {
this.status = status;
}

@Override
public void run() {
System.out.println("start download");
for (int i = 0; i < 10_000; i++) { //"download" a 10,000 bytes file each time you run
status.increment(); //each byte downloaded - update the status
}
System.out.println("download ended with: " + status.getTotalBytes()); //**NOTE THIS LINE**
status.done();
}
}
//creating threads, one to download, another to wait for the download to be done.
public static void main(String[] args) {
DownloadStatus status = new DownloadStatus();

Thread t1 = new Thread(new DownloadFileTask(status));
Thread t2 = new Thread(() -> {
while (!status.isDone()) {}
System.out.println("DONE!!");
});

t1.start();
t2.start();
}

因此,运行它会产生可见性问题 - 第二个线程不会看到更新的值,因为它在第一个线程写回之前已经缓存了它 - 这会导致无限(while)循环,第二个线程不断检查缓存的 isDone()。 (至少我认为它是这样工作的)。

我不明白的是,为什么当我注释掉第二个代码块中调用 status.getTotalBytes() 的行时,这个可见性问题就不再发生。根据我的理解,两个线程都是从按原样缓存状态对象开始的,因此第二个线程应该不断检查他的缓存值(并且基本上看不到第一个线程更新的新值)。

为什么此行调用状态对象中的方法会导致此可见性问题? (更有趣的是 - 为什么不调用它来修复它?)

最佳答案

您所说的“可见性问题”实际上是数据竞争。

单个线程按照其写入的顺序查看其操作的效果。也就是说,如果您更新变量然后读取它,您将始终在该线程中看到更新的值。

从另一个线程的角度来看,一个线程的执行效果可能会有所不同。这主要与语言和底层硬件架构有关。编译器可以重新排序指令,延迟存储器写入,同时将值保留在寄存器中,或者可以在写入主存储器之前将值保留在高速缓存中。如果没有显式内存屏障,主内存中的值将不会被更新。这就是您所说的“可见性问题”。

System.println 中可能存在内存障碍。因此,当您执行该行时,截至该点的所有更新都将提交到主内存,并且其他线程可以看到它。请注意,如果没有显式同步,仍然无法保证其他线程会看到它,因为这些线程可能会重复使用它们之前为该变量获取的值。程序中没有任何内容告诉编译器/运行时这些值可能会被其他线程更改。

关于java - Java 缓存整个对象还是仅缓存对象的一部分? (可见性问题),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60762064/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com