在 Java 中模拟场能见度问题
Simulating Field-visibility problem in Java
我正在阅读 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);
}
}
编辑
我在FieldVisibility
中添加了一个新变量condition
,默认值为true
。接下来,我在 WriterThread
中将其值设置为 false
,但是,相同的值 (false) 仍然传播到 ReaderThread
,所以我仍然无法模拟它。
原创
我预计在某个时候 ReaderThread
将无法 "see" 变量 x
的最新值,但我每次 运行 都看到它,它给出了相同的结果.我什至 运行 在调试模式下,暂停 ReaderThread
而 运行 宁 WriterThread
连续。但这也没有阻止 ReaderThread
获得最新值。我预计我需要将变量 x
声明为 volatile 以便 ReaderThread
读取 x
.
的最新值
如何模拟 field visibility
概念,或者我需要为此做哪些更改?
您的示例不起作用,因为 System.out.println()
使用共享资源 (System.out
),因此它将与同一资源的其他使用同步。
因此您永远不会*看到一个线程使用另一个线程的旧值的结果。 (*理论上,reader 可以在 x++
和相应的 System.out.println()
之间读取 x
这是一个使用旧值的示例:
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());
}
}
如果你运行这个代码,它会显示线程在最后仍然是运行ning。如果没有 t.setDaemon(true)
,VM 将等待线程完成,这永远不会发生。
如果您注释掉 Thread.sleep
,那么新线程可能会终止(至少在我的测试中是这样),但不保证一定会终止。
解决此问题的正确方法是声明 stop
volatile
.
或者加个内存屏障。
我正在阅读 Java 的内存模型教程之一,并遇到了多线程编程中出现的 field visibility
这个概念。我尝试使用下面的代码模拟相同的内容,但是,我在每个线程中看到,最新的值正在反映(在 ReaderThread 中)。
下面是完整的程序。
编辑
在一些使用 while(somevariable) 的建议之后,我合并了,但仍然得到相同的行为。我在阅读 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
,所以我仍然无法模拟它。
原创
我预计在某个时候 ReaderThread
将无法 "see" 变量 x
的最新值,但我每次 运行 都看到它,它给出了相同的结果.我什至 运行 在调试模式下,暂停 ReaderThread
而 运行 宁 WriterThread
连续。但这也没有阻止 ReaderThread
获得最新值。我预计我需要将变量 x
声明为 volatile 以便 ReaderThread
读取 x
.
如何模拟 field visibility
概念,或者我需要为此做哪些更改?
您的示例不起作用,因为 System.out.println()
使用共享资源 (System.out
),因此它将与同一资源的其他使用同步。
因此您永远不会*看到一个线程使用另一个线程的旧值的结果。 (*理论上,reader 可以在 x++
和相应的 System.out.println()
x
这是一个使用旧值的示例:
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());
}
}
如果你运行这个代码,它会显示线程在最后仍然是运行ning。如果没有 t.setDaemon(true)
,VM 将等待线程完成,这永远不会发生。
如果您注释掉 Thread.sleep
,那么新线程可能会终止(至少在我的测试中是这样),但不保证一定会终止。
解决此问题的正确方法是声明 stop
volatile
.
或者加个内存屏障。