java - 在 Java 中模拟 Field-visibility 问题

标签 java multithreading volatile

我正在阅读有关 Java 内存模型的教程之一,并遇到了在多线程编程中发生的字段可见性的概念。我尝试使用下面的代码模拟相同的内容,但是,我在每个线程中看到,最新的值正在反射(reflect)(在 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 将无法“看到”变量 x 的最新值,但我每次运行它时都看到它给出了相同的结果.我什至在 Debug模式下运行,在连续运行 WriterThread 的同时暂停 ReaderThread 。但这也没有阻止 ReaderThread 获得最新值。我预计我需要将变量 x 声明为 volatile 以便 ReaderThread 读取 x 的最新值。

如何模拟字段可见性概念,或者我需要为此做哪些更改?

最佳答案

您的示例不起作用,因为 System.out.println() 使用共享资源 (System.out),因此它将与其他使用同步相同的资源。

因此,您永远不会*看到一个线程使用另一个线程的旧值的结果。 (*理论上,读者可以在 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());
    }
}

如果运行这段代码,最后会显示线程还在运行。如果没有 t.setDaemon(true),VM 将等待线程完成,这永远不会发生。

如果您注释掉 Thread.sleep,那么新线程可能会终止(至少在我的测试中是这样),但不保证一定会终止。
解决此问题的正确方法是声明 stop volatile
或者添加内存屏障。

关于java - 在 Java 中模拟 Field-visibility 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58041588/

相关文章:

ios - Unwind Segue 和多线程

java - 在Jetty HttpClient Hang上寻求建议

c - 当变量在中断例程中改变时,是否真的需要 volatile 关键字

java - 如何更改 json 对象名称(键)?

java - 当内存有问题时如何修改大型 Excel 文件

java - CompletableFuture没有得到执行。如果我使用ExecutorService池,则其工作正常,但不使用默认的forkJoin公共(public)池

java - 再次设置 AtomicBoolean

c++ - 使用 clang 对 std::atomic 函数的调用不明确

java - 将 JSONObject 转换为 Java 对象

java - 在多个 XML 文件中拆分 XML