Вопрос о модели памяти Java - PullRequest
2 голосов
/ 02 июня 2009

Я знаю, может быть, ответ на вопрос очевиден. Но если кто-нибудь может дать мне окончательный ответ, это было бы полезно.

Вопрос в том, может ли пакет Java NIO обеспечить некоторую гарантию целостности памяти?

Сценарий:

Thread A                                                    Thread B
[modify Object X]                                        
[Send a request A over TCP by NIO]
                                              [receive response for request A over TCP by NIO]
                                              [read Object X]

Является ли изменение, сделанное потоком A, видимым для потока B, если приложение не выполняет синхронизацию / безопасную контрольную пульсацию между потоком A и потоком B.

Большое спасибо за вашу помощь.

Ответы [ 3 ]

5 голосов
/ 02 июня 2009

JMM категорически не дает никаких гарантий в отношении этого сценария. Если только два потока не синхронизируют на одном и том же объекте , между двумя потоками не будет гарантии «произойдет раньше». Таким образом, даже несмотря на то, что вы можете продемонстрировать, что изменения в X в A действительно происходят до чтения X в B в хронологическом порядке , нет никакой гарантии, что B увидит внесенные изменения будут отсутствовать A синхронизация на том же объекте.

Кэширование процессора вступает в игру здесь; B может очень хорошо видеть устаревшие значения в X, потому что кэши не были записаны обратно в основную память (пока).

Ваш код может работать на некоторых аппаратных конфигурациях и очень редко давать сбой на других. Системы SMP со слабой памятью особенно подвержены сбоям (вспомним DEC Alpha).

5 голосов
/ 02 июня 2009

Я полагаю, что запрос TCP не дает никаких формальных гарантий относительно синхронизации потоков.

Тем не менее, я думаю, что есть простое решение проблемы, которую вы поднимаете: разумно предположить, что TCP-запрос, по крайней мере, такой же дорогой (с точки зрения производительности), как и получение блокировки. Следовательно, вы можете заключить отправку / получение в синхронизированный блок без существенного снижения производительности. Это гарантирует, что поток B увидит объект X после того, как он был изменен.

1 голос
/ 02 июня 2009

номер

Это не гарантировано.

Вы должны синхронизироваться по X, чтобы обеспечить целостность. Обратите внимание, что вам следует избегать включения фактической отправки и получения в синхронизированный блок.

Thread A 
synchronize( X ) {                                               Thread B
    [modify Object X]
    [build request A using data from X]
}                                        
[Send a request A over TCP by NIO]

                                          [receive response for request A over TCP by NIO]
                                              [read Object X] // assuming from a synchronized database or collection.

                                          synchronize( x ) { 
                                              [handle the response]
                                          }
                                          [call methods in other objects]

Если обрабатывается ответ в потоке B, используйте состояние в X, чтобы убедиться, что вы можете обработать сообщение.

Если вам нужно вызывать другие части системы, которые также используют подобные блокировки и могут вызывать методы в X, вам нужно проделать определенную работу, чтобы убедиться, что вы не получите тупик. Например, убедитесь, что вы можете снять блокировку перед вызовом других объектов.

...