通过最终方法论证安全发布?

时间:2016-05-10 11:26:27

标签: java multithreading

Java Concurrency in Practice 描述了几种确保对象安全发布的方法,其中之一是“分配给正确构造的对象的最终字段”。我的问题是,最终方法论证的赋值是否足以确保安全发布。请考虑以下代码:

private void collectResults() {
    runOnBackgroundThread(new Runnable() {
        public void run() {
            displayResults(someBlockingMethodCall());
        }
    });
}

private void displayResults(final List<Foo> results) {
    runOnUiThread(new Runnable() {
        public void run() {
            someUiMethodCall(results);
        }
    });
}

每个方法将Runnable排队等待在另一个线程上执行。在后台线程上调用someBlockingMethodCall()来执行某项任务,并在UI线程上调用someUiMethodCall()来显示结果。

如果我们假设someBlockingMethodCall()返回一个可变的,不同步的列表(例如ArrayList),则会对displayResults()的最终参数进行赋值,以确保列表安全发布,或者我是否需要确保安全发布的额外步骤?

2 个答案:

答案 0 :(得分:3)

你真的很好。如果将results写入未同步的共享变量,则唯一需要真正担心的时间。

要将其交给线程,通常应该有一些同步。例如,如果您启动了一个帖子并且results已传递给Runnable,则该帖子的start就是您需要的同步点。

在这种情况下,您正在调用runOnUiThread,从您提交results到线程获取它的那一刻有一个同步点。

所以这里的提交将是线程安全的。

答案 1 :(得分:0)

这里有几个误解。 this字段发布保证允许程序员正确地使用不可变对象,即使它们被不正确地发布。这并不意味着您应该围绕不正确发布的对象设计软件。

通常,public A b(string a) { //Do stuff return this; } final应该以线程安全的方式将runOnUiThread实例发布到正在执行的线程,因此,不需要依赖{{1}字段发布。这两种方法是否正确,我们不可能告诉你,因为你没有发布他们的代码。

此外,正如您正确引用的那样,保证适用于“对正确构造的对象的最终字段的赋值”,而局部变量(包括参数)不是任何构造对象的字段。但这并不值得担心,因为参数是执行该方法的线程的任何局部变量 local ,因此根本不会发布。

这里有一个极端情况,因为您在创建匿名runOnBackgroundThread实现的实例时捕获局部变量的值。这种捕获确实具有Runnable字段赋值语义,无论参数是否已被声明final或只是有效最终

但是,如上所述,这不应该推动您的软件设计。您应确保Runnablefinal正确发布其runnable,而不是考虑最终的字段发布。如果这些方法没有正确发布提供的runnables,则可能会出现其他问题,但如果这样做,则runnables引用的任何对象的发布也会正确发布。这一切都假设您在发布后不修改列表。