2016-05-10 1 views
2

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() вызывается в фоновом потоке для выполнения некоторой задачи, а someUiMethodCall() вызывается в потоке пользовательского интерфейса для отображения результатов.

Если мы предположим, что someBlockingMethodCall() возвращает изменяемый, несинхронизированный список, например, как ArrayList, делает назначение окончательного аргумента displayResults() гарантировать, что список благополучно опубликовано, или мне нужно принять дополнительные меры для обеспечения безопасной публикации?

+0

Это только «конечные» поля, которые имеют значение. Для аргументов метода, а также для локальных переменных (которые в основном одинаковы) единственное, что вы получаете, это ошибка при попытке переназначить значение. – zapl

ответ

3

Вы на самом деле отлично здесь. Единственный раз, когда вам нужно действительно беспокоиться об этом, если вы напишете results для общей переменной, которая не синхронизирована.

Чтобы передать его в поток, обычно должна быть какая-то синхронизация. Например, если вы начали поток, и results был передан Runnable, то start потока - это точка синхронизации, в которой вы нуждаетесь.

В этом случае вы вызываете runOnUiThread, есть точка синхронизации с момента отправки results до точки, где поток ее подбирает.

Таким образом, представление здесь будет потокобезопасным.

+0

Спасибо, Джон! Мне не пришло в голову, что, конечно, методы, передающие объект между фоном и потоками пользовательского интерфейса, должны использовать синхронизацию, и поэтому объект будет безопасно опубликован без каких-либо дополнительных мер предосторожности. – akwizgran

+0

@akwizgran Рад помочь. Я всегда говорю, что в конце концов понимают многопоточное программирование, когда они явно параноичны многопоточного программирования :) –

0

Существует несколько неправильных представлений. Гарантию публикации в полевых условиях final предоставляется, чтобы позволить программисту правильно использовать неизменяемые объекты, даже если они были неправильно опубликованы. Это не означает, что вы должны проектировать свое программное обеспечение вокруг неправильно опубликованных объектов.

Как правило, runOnUiThread и runOnBackgroundThread должны вывесить Runnable экземпляров исполняющей нить в поточно-образом, следовательно, нет необходимости полагаться на публикации final поля. Правильны ли эти два метода, мы не можем сказать, поскольку вы не отправляли их код.

Кроме того, гарантия, как вы правильно указали, относится к «присвоению окончательному полю правильно построенного объекта», а локальные переменные (включая параметры) не являются полями какого-либо построенного объекта. Но об этом не о чем беспокоиться, поскольку параметры, как и любая локальная переменная, local в поток, выполняющий метод, следовательно, не публикуются вообще.

Здесь есть угловой случай, так как вы являетесь , фиксируя значение локальной переменной при создании экземпляра анонимной реализации Runnable. Этот захват действительно содержит семантику назначения полей final и что независимо от того, был ли объявлен параметр final или просто эффективно окончательный.

Но, как сказано, это не должно вести дизайн вашего программного обеспечения. Вы должны убедиться, что runOnUiThread и runOnBackgroundThread действительно публикуют свои runnables должным образом вместо того, чтобы думать о окончательной публикации поля.Если эти методы не публикуют предоставленные runnables должным образом, могут возникнуть другие проблемы, но если они это сделают, публикация любого объекта, на который ссылаются runnables, также опубликована правильно. Все это предполагает, что вы не изменяете список после публикации.

+0

Как новый пользователь, мои подсказки не видны, поэтому я просто хотел сказать спасибо Хольгеру за этот очень информативный ответ, особенно подробно о семантике захваченных полей. – akwizgran

Смежные вопросы