【问题标题】:Java: Thread safety of passing value to inner classJava:将值传递给内部类的线程安全
【发布时间】:2016-03-22 20:48:47
【问题描述】:

因此,我需要为公司应用程序的一部分编写密集操作,使其远离 UI 线程(我们使用 Swing),并与一大堆高度线程不安全的组件进行交互.欢乐时光。

我正在尝试为自己简化这一点。所以事情是这样的:

1) 来自线程不安全组件的数据只会被读取,不会被写入。

2) 对该数据的引用将被传递给后台线程,如下所示:

final Object someData = getSomeData();
        Runnable task = new Runnable() {
            @Override
            public void run() {
                doSomething(someData);
            }
        };

此外,模式对话框会阻止用户在此过程中无意中更改任何值。所以 someData 的状态在整个过程中不会改变,只是被读取。

所以,我总是对内存一致性问题非常偏执。这里会有吗?通过以这种方式传递引用,后台线程是否会在此时获得它的最新状态?

谢谢。

【问题讨论】:

  • 如果这就是您的意思,参考不会过时。每次使用它时,它都会反映当前状态。
  • 我会先克隆 someData,然后再将其传递给线程。当线程完成对该数据的处理后,您可以将结果传递回 UI。
  • 内部类与它没有任何关系。问题是第二个线程,它需要通常的线程安全预防措施:synchronizedvolatile
  • 我知道,但是正确同步这个对象几乎是不可能的。想象一下可以想象到的最糟糕的意大利面条代码。我可以确保在此过程中不会对 someData 进行任何写入,但如果我以上述方式将其传递给该后台线程,我是否能够正确读取其当前状态?

标签: java web-services rest ssl


【解决方案1】:

如果您正在使用 Runnable 启动新线程,或者将其提交给 Executor,那么新线程将看到在创建线程之前发生的所有操作。因此,只要在后台线程运行时状态没有改变,那么您的数据将是可见的。使用不可变对象会更容易保证。

Executor:

内存一致性效果:线程中的操作在将 Runnable 对象提交给 Executor 之前发生在其执行开始之前,可能在另一个线程中。

Thread.start:

当一个语句调用 Thread.start 时,与该语句具有发生前关系的每个语句也与新线程执行的每个语句具有发生前关系。导致创建新线程的代码的效果对新线程是可见的。

为了将数据发送回 UI 线程,如果更改通过 invokeLater,您将获得可见性保证。见Is happens-before relation given in case of invokeLater() or invokeAndWait?

如果您使用Swing Worker,其中一些是为您管理的。这允许您覆盖一个在后台线程中运行的方法,然后在事件调度线程完成后覆盖另一个在事件调度线程中运行。

【讨论】:

  • 非常感谢。这正是我一直在寻找的答案。通过使用模态对话框(关闭它们的能力),我可以防止在此过程中对应用程序状态进行任何更改。这不是最优雅的解决方案,但在我的公司开始完全重写代码之前,它是我拥有的最佳选择。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-29
  • 1970-01-01
  • 2014-01-05
  • 1970-01-01
  • 2011-11-23
  • 1970-01-01
相关资源
最近更新 更多