2015-11-23 3 views
2

application.temporaryStory является глобально видимым Story объектом, из которого не менее 2 потоков могут писать и читать.Будет ли синхронизированный блок помочь мне в этой ситуации?

В адаптере у меня есть этот код;

 synchronized (this){ 
      if(application.temporaryStory!=null){ // Line A 
       application.temporaryStory.setLastImageViewed(position); // Line B 
      } 
     } 

Этот код выполнен в основном потоке. Возможно ли, несмотря на синхронизированный блок, для рабочего потока обнулить объект application.temporaryStory между проверочной линией A и кодом в строке B?

+1

если этот рабочий поток не синхронизируется на том же объекте, что и поток, который выполняет линию A/B да. весь доступ к временному хранилищу должен быть синхронизирован с одним и тем же объектом! – ParkerHalo

+1

Могу ли я синхронизировать каждое чтение/запись в application.temporaryStory на самой временной странице? –

+0

Я думаю, что это должно быть возможно! – ParkerHalo

ответ

2

Вам необходимо синхронизировать все операции операции чтения и записи объекта на одном и том же объекте монитора. В противном случае это is возможно для других потоков, чтобы изменить значение, пока текущий поток запущен. Поэтому я бы предложил использовать application здесь, так как это, кажется, «владелец» temporaryStory:

synchronized (this){ 
    if(application.temporaryStory!=null){ 
     application.temporaryStory.setLastImageViewed(position); 
    } 
} 

Было бы еще лучше, если бы вы инкапсулировать temporaryStory где-то (например, в приложении, но может быть, есть лучше место), поэтому он доступен только через синхронизированные методы.

Но для этого вам необходимо переместить весь код, который должен получить доступ к temporaryStory атомным способом к классу инкапсуляции. Таким образом, код из вашего примера нужно будет перейти в класс Application:

public synchronized void setLastImageViewed(...) { 
    if(application.temporaryStory!=null){ // Line A 
     application.temporaryStory.setLastImageViewed(position); 
    } 
} 

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

+0

Могу ли я обернуть объект Story, который является временнымStory в другом объекте, который синхронизирует все операции чтения/записи с ним? –

+0

@ J.K. да, я только что обновил свой ответ. Будет добавлено немного больше деталей за минуту;) –

3

Да, это возможно: В связи с тем, что этот блок является внешне синхронизируются, было бы достаточно с синхронизирован вызова, чтобы сделать его из строя.

Основная причина всего этого - публиковать публичные переменные-члены. Хорошая практика программирования побуждает к тому, чтобы все переменные были приватными, и, если необходимо, подвергать их публичным методам.

Update

Так что, если вместо публичного переменной temporaryStore вы имели один публичный метод для каждой операции требуется быть атомарными, вы могли бы ввести внутренние синхронизации в эти методы, защищая всяческий доступ к temporaryStore объекту ,

В вашем случае, вам нужно:

public void setLastImageViewed(position) 
{ 
    synchronized (this){ 
     if(application.temporaryStory!=null){ // Line A 
      application.temporaryStory.setLastImageViewed(position); // Line B 
     } 
    } 
} 
+0

, так что если бы у меня была getTemporaryStory, которая возвращает историю в синхронизированном блоке, а setTemporaryStory, которая задает историю в синхронизированном блоке, у меня не было бы проблем? –

+0

Это не совсем правильно. Метод getTemporaryStore не поможет с обновлением после ошибки чтения. Вам нужно будет переместить весь код, который должен запускаться атомарно в класс, который инкапсулирует временную структуру. –

+0

Я должен согласиться с Дэвидом Танзером. См. Мое обновление. –

1

Если вы используете AtomicReference вместо этого, вы можете обойтись без явной синхронизации:

public final AtomicReference<Story> temporaryStoryHolder = new AtomicReference<>(); 

(отметив, что это final, так вы не можете обнулить temporaryStoryHolder, но вы все равно можете изменить его содержимое).Затем

Story temporaryStory = temporaryStoryHolder.get(); 
if (temporaryStory != null) { 
    temporaryStory.setLastImageViewed(position); 
} 
Смежные вопросы