在 Java 中模拟 Field-visibility 问题 [英] Simulating Field-visibility problem in Java
问题描述
我正在阅读有关 Java 内存模型的教程之一,并遇到了在多线程编程中发生的字段可见性
的概念.我尝试使用以下代码模拟相同的内容,但是,我在每个线程中看到,最新值正在反映(在 ReaderThread 中).
I was going through one of the tutorials on memory model of Java and came across this concept of field visibility
which happens in multi-threaded programming. I tried to simulate the same using the below code, however , I see in each thread, the latest value is being reflected (in ReaderThread).
以下是完整的程序.
在使用 while(somevariable) 的一些建议之后,我合并了,但仍然得到相同的行为.我在阅读 x
After some suggestion to use while(somevariable), I incorporated, but still getting the same behaviour. I removed sysout on reading the x
FieldVisibility.java
package com.example.threads.fieldvisibility;
public class FieldVisibility {
private int x;
private boolean condition;
public FieldVisibility() {
condition = true;
}
public void reader() {
System.out.println("x in reader() is " + x);
}
public void writer() {
x++;
}
public boolean getCondition() {
return condition;
}
public void setCondition(boolean condition) {
this.condition = condition;
}
}
ReaderThread.java
package com.example.threads.fieldvisibility;
public class ReaderThread extends Thread {
private FieldVisibility fv;
public ReaderThread(FieldVisibility fv) {
this.fv = fv;
}
@Override
public void run() {
while (fv.getCondition()) {
System.out.println("It mean condition is true, which was set initially");
}
for (;;) {
}
}
}
WriterThread.java
package com.example.threads.fieldvisibility;
public class WriterThread extends Thread {
private FieldVisibility fv;
public WriterThread(FieldVisibility fv) {
this.fv = fv;
}
@Override
public void run() {
fv.setCondition(false);
for (;;) {
fv.writer();
}
}
}
MainApp.java
package com.example.threads.fieldvisibility.main;
import com.example.threads.fieldvisibility.FieldVisibility;
import com.example.threads.fieldvisibility.ReaderThread;
import com.example.threads.fieldvisibility.WriterThread;
public class MainApp {
public static void main(String[] args) throws InterruptedException {
FieldVisibility fv = new FieldVisibility();
ReaderThread rt = new ReaderThread(fv);
WriterThread wt = new WriterThread(fv);
wt.start();
rt.start();
Thread.sleep(999999999L);
}
}
编辑
我在FieldVisibility
中添加了一个新变量condition
,默认值为true
.接下来,我在 WriterThread
中将它的值设置为 false
,但是,相同的值(false)仍然传播到 ReaderThread
,所以我仍然是无法模拟它.
Edit
I added a new variable condition
in FieldVisibility
, whose default values is true
. Next, I set its value to false
in WriterThread
, however, the same value (false) is still propagated to ReaderThread
, so I still am not able to simulate it.
原创我预计在某个时候 ReaderThread
将无法看到"变量 x
的最新值,但是我每次运行它时都看到,它给出了相同的结果.我什至在调试模式下运行,在连续运行 WriterThread
的同时暂停 ReaderThread
.但这也没有阻止 ReaderThread
获得最新值.我希望我需要将变量 x
声明为 volatile 以便 ReaderThread
读取 x
的最新值.
Original
I expected that at some time ReaderThread
won't be able to "see" the latest value of variable x
, but I saw every time I run it, it gave same results. I even run in debug mode, suspended ReaderThread
while running WriterThread
continuously. But that also didn't prevent ReaderThread
to have latest values. I expected that I need to declare variable x
as volatile in order for ReaderThread
to read latest values of x
.
我如何模拟字段可见性
的概念,或者我需要为此做哪些改变?
How can I simulate the field visibility
concept, or what changes I need to do for this?
推荐答案
您的示例不起作用,因为 System.out.println()
使用共享资源 (System.out
),所以它会与同一资源的其他用途同步.
Your example doesn't work because System.out.println()
uses a shared resource (System.out
), so it will synchronize with other uses of the same resource.
因此,您永远不会*看到一个线程使用另一个线程的旧值的结果.(*理论上读者可以在x++
和对应的System.out.println()
Therefore you will never* see a result where one thread uses the old value of the other. (*in theory it is possible for the reader to read x
between x++
and the corresponding System.out.println()
以下是使用旧值的示例:
Here is an example where a old value is used:
public class ThreadVisibility implements Runnable {
private boolean stop = false;
@Override
public void run() {
while (!stop);
}
public static void main(String[] args) throws InterruptedException {
ThreadVisibility test = new ThreadVisibility();
Thread t = new Thread(test);
t.setDaemon(true);
System.out.println("Starting Thread");
t.start();
Thread.sleep(1000);
System.out.println("Stopping Thread");
test.stop = true;
t.join(1000);
System.out.println("Thread State: " + t.getState());
}
}
如果你运行这段代码,最后会显示线程仍在运行.如果没有 t.setDaemon(true)
,VM 将等待线程完成,这永远不会发生.
If you run this code, it will display that the thread is still running at the end. Without the t.setDaemon(true)
, the VM would wait for the Thread to finish, which would never happen.
如果您注释掉 Thread.sleep
,那么新线程可能会终止(至少在我的测试中是这样),但不能保证会终止.
解决此问题的正确方法是声明 stop
volatile
.
或者添加一个内存屏障.
If you comment out the Thread.sleep
, then the new Thread may terminate (at least it did in my tests), but it is not guaranteed to.
The right fix for this problem is to declare stop
volatile
.
Or add a memory barrier.
这篇关于在 Java 中模拟 Field-visibility 问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!