我浏览了有关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
或添加内存障碍。

08-18 07:33