java - 线程执行的频率是多少?我的观察者模式出错了?

标签 java multithreading

以下是我当前代码的简化版本。我很确定我在语法方面没有做错任何事情,而且我找不到我的概念错误。

这是我尝试实现的一种观察者模式。我负担不起从 Java.utils.observable 继承,因为我的类已经很复杂并且继承自另一个类。 这里有两个部分:

有一个实现 Runnable 的 Notifier 类:

public class Notifier implements Runnable{

    public void run()
    {
        while(true)
        {
            MyDataType data = getData();
            if(data.isChanged()==true)
            {
                refresh();
            }
        }
    }
}

然后是我的主类,它需要响应对 MyDataType 数据的更改。

public class abc {

    private MyDataType data;

    public void abc(){
               Notifier notifier = new Notifier();
               Thread thread = new Thread(notifier);
               thread.start();
          }     


    public MyDataType getData(){
              return this.data;
    }


    public void refresh(){
         MyDatatype data = getData();
     //Do something with data
    }
}

问题:发生的事情是通知程序在“数据”更改时调用 refresh()。但是在 refresh() 中,当我执行 getData() 时,我得到的是旧版本的“数据”! 我应该提到代码的其他部分也在调用 refresh() 函数。

  • 我忽略了什么?
  • 对于此问题还有其他更好的解决方案吗?
  • 如果我不能开箱即用地应用默认的 Java 实现,我应该如何设计主题-观察者系统?

最佳答案

when I do getData(), I am getting the old version of 'data'!

您的 data 字段由多个线程共享,因此必须用 volatile 关键字标记。

private volatile MyDataType data;

这会导致围绕读取和写入的“内存屏障”,使值对所有线程可见。即使通知程序线程正在调用 getData()data 的值也会在其内存缓存中被检索出来。如果没有内存屏障,data 值将随机更新或从不更新。

正如@JB 在评论中提到的,volatile 保护您免受data 字段的重新分配。如果您更新 current data 值中的字段之一,则不会跨越内存屏障,通知程序的内存不会被更新。

回顾一下你的代码,看起来是这样的:

if(data.isChanged()==true)
{
    refresh();
}

如果 data 没有被分配给一个新对象,那么将 data 设置为 volatile 将无济于事。您将必须:

  • 每当 data 更新时,设置某种 volatile boolean dirty; 字段。
  • 每次都更新或读取 synchronize block 中的 data

关于java - 线程执行的频率是多少?我的观察者模式出错了?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10985874/

相关文章:

Java + 线程 : processing lines in parallel

c# - 等待 HttpWebRequest.BeginGetRequestStream 结束

c++ - 在 NUMA 节点之间传播 OpenMP 线程

java - 确保一类中只有一个线程

java - @sun.misc.Contended 注释的值是多少?

java - 如何验证(通过单元测试)错误堆栈是否打印在日志文件中?

java - hibernate c3p0 ThreadPoolExecutor 连接池,我做对了吗?

java - 是否可以在 spring batch 中跨单个文件进行分区?

创建本地和实例对象时出现 java StackOverflowError

java - 如何在不超过最大值的情况下增加变量?