|
|
|
Товарищ не понимает
|
|||
|---|---|---|---|
|
#18+
Добрый день Помогите, пожалуйста, разобраться с примером из книги Brian Goetz "Java Concurrency in Practice" В главе 3.5 Safe Publication он пишет You cannot rely on the integrity of partially constructed objects. An observing thread could see the object in an inconsistent state, and then later see its state suddenly change, even though it has not been modified since publication. In fact, if the Holder in Listing 3.15 is published using the unsafe publication idiom in Listing 3.14, and a thread other than the publishing thread were to call assertSanity, it could throw AssertionError! и далее... ...thread may see a stale value the first time it reads a field and then a more up-to-date value the next time, which is why assertSanity can throw AssertionError Listing 3.14 Код: plaintext 1. 2. 3. 4. 5. 6. Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. То есть, если я правильно понял, какой-нибудь поток вызывает holder.assertSanity(), читает левое n==42, прерывается, а потом читает правое n, то оно уже может не быть 42 Как такое может случиться с классом Holder в том виде как он написан в Listing 3.15? Большое спасибо ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2007, 15:05:39 |
|
||
|
Товарищ не понимает
|
|||
|---|---|---|---|
|
#18+
02... Как такое может случиться с классом Holder в том виде как он написан в Listing 3.15? Большое спасибо Он как раз и написан так чтобы это могло случиться :) в том и смысл, что unsafe publication может приводить к подобным казусам. Разные потоки в такой ситуации в разные моменты времени могут видеть все что угодно. Подробности в JSR-133 (Java memory model). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2007, 15:20:10 |
|
||
|
Товарищ не понимает
|
|||
|---|---|---|---|
|
#18+
Timm В соответствии с JMM, по-моему разумению, с точки зрения какого-нибудь потока n может может быть равным любому из значений, записанных в это n другими потоками Но в данном случае, кто может что-нибудь записать в n после initialize()? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2007, 15:39:07 |
|
||
|
Товарищ не понимает
|
|||
|---|---|---|---|
|
#18+
Даже если какой-то поток влезет между чтением левого n и правого n и скажет holder= new Holder(43), это же не изменит правое n? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2007, 16:16:01 |
|
||
|
Товарищ не понимает
|
|||
|---|---|---|---|
|
#18+
02Timm В соответствии с JMM, по-моему разумению ... Но в данном случае, кто может что-нибудь записать в n после initialize()? У JVM другое разумение. Фокус не в том что кто то еще может записать туда, а в том что поток может не увидеть эти изменения сразу, и нет никаких гарантий на то какое значение в какой момент времени читающий поток будет видеть. Так понятно? В книжке чуть ниже ведь написано: Because synchronization was not used to make the Holder visible to other threads, we say the Holder was not properly published. Two things can go wrong with improperly published objects. Other threads could see a stale value for the holder field, and thus see a null reference or other older value even though a value has been placed in holder. But far worse, other threads could see an up-todate value for the holder reference, but stale values for the state of the Holder.[16] To make things even less predictable, a thread may see a stale value the first time it reads a field and then a more up-to-date value the next time, which is why assertSanity can throw AssertionError. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2007, 16:38:14 |
|
||
|
Товарищ не понимает
|
|||
|---|---|---|---|
|
#18+
Есть например поток А, он вызвал метод initialize() и отработал его от начала и до конца, затем запускается поток В и вызывает метод assertSanity(), доходит то места, где считывает первую переменную n, затем прерывается потоком C, который вызывает метод initialize(), отработал его от начала и до конца, т.е. создает новый объект holder. Затем управление передается опять потоку B и получается так, что он находится внутри метода объекта, которого нет и об этом потоку B никак не сообщается и продолжает читать вторую n, в которой может быть все что угодно. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2007, 16:52:03 |
|
||
|
Товарищ не понимает
|
|||
|---|---|---|---|
|
#18+
Есть такие люди тупые и надоедливые Так это я Тимм Если поток А инициализирует holder, до этого еще не инициализированную, то поток В, намеревающийся вызвать holder.assertSanity(), или обламывается, если к этому моменту holder все еще ==null, или видит в holder все, что сделал поток А. Ведь нельзя же в потоке В увидеть holder != null, ссылающийся на не инициализированный или частично инициализированный обьект Holder? wessen Затем управление передается опять потоку B и получается так, что он находится внутри метода объекта, которого нет и об этом потоку B никак не сообщается и продолжает читать вторую n, в которой может быть все что угодно. Почему же это которого нет. Он есть и на него указывает this, то есть та ссылка, на которой assertSanity() в потоке В был вызван??? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2007, 17:34:48 |
|
||
|
Товарищ не понимает
|
|||
|---|---|---|---|
|
#18+
02Есть такие люди тупые и надоедливые Так это я Тимм Если поток А инициализирует holder, до этого еще не инициализированную, то поток В, намеревающийся вызвать holder.assertSanity(), или обламывается, если к этому моменту holder все еще ==null, или видит в holder все, что сделал поток А. Ведь нельзя же в потоке В увидеть holder != null, ссылающийся на не инициализированный или частично инициализированный обьект Holder? Можно!! Варианты: 1. holder == null 2. holder != null && n = 0 3. holder != null && n = 42 4. holder != null && n = <что то еще> + состояние объекта при чтении в разные моменты времени может быть разным. Первые три случая могут быть. Насчет четвертого я не уверен. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2007, 17:53:35 |
|
||
|
Товарищ не понимает
|
|||
|---|---|---|---|
|
#18+
Time-out Надо подумать ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2007, 18:04:40 |
|
||
|
Товарищ не понимает
|
|||
|---|---|---|---|
|
#18+
02 Почему же это которого нет. Он есть и на него указывает this, то есть та ссылка, на которой assertSanity() в потоке В был вызван??? В том то и дело, что поток С вызвав метод initialize() переписал эту ссылку, и та область данных(объект handle, который создал поток А), которую все еще использует поток В, объявлена как неиспользованая и ее в любой момент может занять любой другой поток. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2007, 18:11:10 |
|
||
|
Товарищ не понимает
|
|||
|---|---|---|---|
|
#18+
wessen В том то и дело, что поток С вызвав метод initialize() переписал эту ссылку, и та область данных(объект handle, который создал поток А), которую все еще использует поток В, объявлена как неиспользованая и ее в любой момент может занять любой другой поток. Я против Когда поток В колбасится внутри assertSanity(), то this -это просто еще одна ссылка на тот обьект, на котором был вызван holder.assertSanity(). Если поток С скажет в это время holder=new Holder(43), то это никак не повлияет на this в потоке В и на обьект, на который this указывает. this это final reference. Поэтому всегда внутри assertSanity() this.n==this.n А то что вы пишите "объявлена как неиспользованая и ее в любой момент может занять любой другой поток.", так это произойдет только после выхода из assertSanity() Разве не так? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2007, 19:49:49 |
|
||
|
Товарищ не понимает
|
|||
|---|---|---|---|
|
#18+
02 А то что вы пишите "объявлена как неиспользованая и ее в любой момент может занять любой другой поток.", так это произойдет только после выхода из assertSanity() Разве не так? Думаю, что не так. Т.к. ссылка на объект, которой владеет поток B, будет объявлена недействительной после того, как поток С выйдет из метода initialize(). И соотвтественно объект handler, которым владеет поток В может быть уничтожен сборщиком мусора в любой момент. Именно из-за этого, во время считывания второй n, в ней может оказаться все, что угодно: старое значение, новое значение или мусор, как говорится "как Бог пошлет". ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2007, 20:13:36 |
|
||
|
Товарищ не понимает
|
|||
|---|---|---|---|
|
#18+
wessenВ том то и дело, что поток С вызвав метод initialize() переписал эту ссылку, и та область данных(объект handle, который создал поток А), которую все еще использует поток В, объявлена как неиспользованая и ее в любой момент может занять любой другой поток. Это невозможно. До тех пор, пока хоть у одного потока есть ссылка на объект - он не может быть разрушен. Просто потоки будут использовать разные ссылки (они обычно в таком случае кэшируются потоками). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2007, 20:19:05 |
|
||
|
Товарищ не понимает
|
|||
|---|---|---|---|
|
#18+
wessenИменно из-за этого, во время считывания второй n, в ней может оказаться все, что угодно: старое значение, новое значение или мусор, как говорится "как Бог пошлет". Утверждение в корне противоречит спецификации JVM. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2007, 20:20:02 |
|
||
|
Товарищ не понимает
|
|||
|---|---|---|---|
|
#18+
2Зашедший Если предположить, что поток В не имеет прямой ссылки на класс Handler и вызывает метод assertSanity() через класс описанный в листинге 3.14. Что произойдет, когда кто-либо еще раз вызовет метод initialize()? По сути, не будет существовать прямой ссылки на объект, в котором все еще находится поток В. Собственно вопрос, gc секёт такие случаи? Если да, тогда и я не знаю как может возникнуть ексепшион в даннолм примере. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2007, 20:43:38 |
|
||
|
Товарищ не понимает
|
|||
|---|---|---|---|
|
#18+
Кажется товарищ понял Если поток А, который сказал holder = new Holder(42); сбросил в heap ссылку holder на только что созданный Holder(42), то это еще не значит, что он уже сбросил туда же и окончательное состояние этого нового Holder(42). Единственное, что поток А может гарантировать, что ничего другого в n кроме default value для int т.е. 0 или 42 быть не может, причем в порядке: сначала 0 потом 42, не наоборот Поэтому из указанных т. Timm вариантов Timm Можно!! Варианты: 1. holder == null 2. holder != null && n = 0 3. holder != null && n = 42 4. holder != null && n = <что то еще> + состояние объекта при чтении в разные моменты времени может быть разным. Первые три случая могут быть. Насчет четвертого я не уверен. поток В, выполняющий assertSanity() может увидеть: в левом n 0, а в правом 0 или 42, в левом 42, тогда в правом только 42 Праильно??? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2007, 22:43:37 |
|
||
|
Товарищ не понимает
|
|||
|---|---|---|---|
|
#18+
02Праильно??? Ну, я б предположил именно такой поворот событий. Второй поток может использовать закешированное им состояние n=0 несмотря на то, что поток-создаватель уже присвоил ему 42, и "подкачать" новое состояние в процессе определения равенства... умереть объект, на который есть ссылка, не может точно :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.03.2007, 23:13:18 |
|
||
|
|

start [/forum/topic.php?fid=59&msg=34404342&tid=2146328]: |
0ms |
get settings: |
22ms |
get forum list: |
29ms |
check forum access: |
9ms |
check topic access: |
9ms |
track hit: |
77ms |
get topic data: |
24ms |
get forum data: |
6ms |
get page messages: |
114ms |
get tp. blocked users: |
3ms |
| others: | 340ms |
| total: | 633ms |

| 0 / 0 |
