атомный вопрос от ядра Java - PullRequest
2 голосов
/ 21 мая 2011

Это раздел из Core Java 8-е издание, стр. 757

ВНИМАНИЕ:

public void flipDone() {
   done = !done;
}

// не атомарно

Я не понимаю, почему это не атомно. Кто-нибудь может сказать мне, почему? спасибо

Ответы [ 5 ]

7 голосов
/ 21 мая 2011

Метод flipDone выполняется компьютером в три этапа:

Read the value of memory location labeled done into ALU
Flip the value (i.e true -> false or false -> true)
Write the new value into the memory location done

В Java фрагмент кода может потенциально вызываться в нескольких потоках.Эти потоки должны рассматриваться как выполняющие код одновременно .

Скажем, область памяти с меткой done изначально содержит значение false.Рассмотрим два потока, вызывающих flipDone, в результате чего получается следующая последовательность шагов:

Thread 1                             Thread 2
-----------------------------------------------------------------------
Read value of done, false
Invert that value to true
Write the new value, true, to done       
                                     Read value of done, now true
                                     Invert that value to false
                                     Write the new value, false, to done

Метод flipDone вызывался дважды.done перешел от false к true, а затем снова к false - как и следовало ожидать.Но поскольку потоки выполняются одновременно, это не единственный порядок шагов.Вместо этого рассмотрим следующий порядок:

Thread 1                             Thread 2
-----------------------------------------------------------------------
Read value of done, false
Invert that value to true            Read value of done, false
Write the new value, true, to done   Invert that value to true    
                                     Write the new value, true, to done

Пока первый поток инвертирует прочитанное значение, второй поток одновременно читает значение.Аналогичным образом, пока первый поток записывает значение в память, второй поток инвертирует значение , которое он считал .Когда Thread 2 заканчивается, значение done будет истинным.Здесь, хотя flipDone был вызван дважды, done был перевернут только один раз!Похоже, что одно из обновлений было потеряно 1030 *.Это проблема, о которой вас предупреждает книга.

6 голосов
/ 21 мая 2011

Здесь три шага:

  1. Считать значение логического done
  2. Инвертировать значение, считанное на шаге 1
  3. Присвойте это значение логическому done

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

4 голосов
/ 21 мая 2011

При выполнении

done = !done;

Что на самом деле происходит:

1. Get the value of done
2. Apply the not operator
3. Assign it to done

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

Например, если было выполнено изначально значение true, после его изменения два раза можно было бы ожидать, что оно все еще верно, но если два потока выполнят шаг 1 вместе, это будет false.

4 голосов
/ 21 мая 2011

Поскольку два потока могут вызывать метод flipDone() одновременно, поэтому состояние переменной done является неопределенным.

0 голосов
/ 21 мая 2011

Он не выполняется как отдельная неделимая операция, а представляет собой последовательность из трех отдельных операций: извлечение текущего значения выполненного, отрицательное значение, запись нового значения обратно в готовое.Это операция read-modify-write, в которой результирующее состояние выводится из предыдущего состояния.

...