我浏览了有关Java内存模型的教程之一,并遇到了field visibility
的概念,该概念发生在多线程编程中。我尝试使用下面的代码来模拟相同的内容,但是,我看到每个线程中的最新值都被反映(在ReaderThread中)。
以下是完整的程序。
编辑在使用了while(somevariable)的一些建议之后,我合并了,但是仍然得到相同的行为。我在阅读x
时删除了sysout
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);
}
}
编辑
我在
condition
中添加了一个新变量FieldVisibility
,其默认值为true
。接下来,我在false
中将其值设置为WriterThread
,但是,相同的值(false)仍会传播到ReaderThread
,因此我仍然无法对其进行模拟。原版的
我希望
ReaderThread
有时无法“看到”变量x
的最新值,但是我每次运行它时都会看到相同的结果。我什至在调试模式下运行,在连续运行ReaderThread
的同时暂停了WriterThread
。但这也不妨碍ReaderThread
具有最新值。我希望我需要将变量x
声明为volatile,以便ReaderThread
读取x
的最新值。谁能帮助您模拟
field visibility
概念或为此需要做哪些更改?感谢您的帮助和提前的时间。
最佳答案
您的示例不起作用,因为System.out.println()
使用共享资源(System.out
),因此它将与同一资源的其他用法同步。
因此,您永远不会*看到一个线程使用另一个线程的旧值的结果。 (*从理论上讲,读者可以在x
和相应的x++
之间阅读System.out.println()
这是一个使用旧值的示例:
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将等待线程完成,这永远不会发生。如果您注释掉
Thread.sleep
,则新线程可能会终止(至少在我的测试中如此),但不能保证终止。解决此问题的正确方法是声明
stop
volatile
。或添加内存障碍。