Что такое состояние гонки?

При написании многопоточных приложений одной из наиболее распространенных проблем является состояние гонки.

Мои вопросы к сообществу:

Что такое состояние гонки?
Как вы их обнаруживаете?
Как вы справляетесь с ними?
Наконец, как вы предотвращаете их возникновение?


person bmurphy1976    schedule 29.08.2008    source источник
comment
Я хотел бы упомянуть, что - без указания языка - на большинство частей этого вопроса невозможно ответить должным образом, потому что на разных языках определение, последствия и инструменты для их предотвращения могут отличаться.   -  person MikeMB    schedule 21.04.2015
comment
@MikeMB. Согласен, за исключением анализа выполнения байтового кода, как это делает Race Catcher (см. Этот поток stackoverflow.com/a/29361427/1363844) мы можем обратиться ко всем примерно 62 языкам, которые компилируются в байтовый код (см. en.wikipedia.org / wiki / List_of_JVM_languages ​​)   -  person Ben    schedule 12.08.2016


Ответы (18)


Состояние гонки возникает, когда два или более потока могут получить доступ к общим данным и пытаются изменить их одновременно. Поскольку алгоритм планирования потоков может переключаться между потоками в любое время, вы не знаете, в каком порядке потоки будут пытаться получить доступ к общим данным. Следовательно, результат изменения данных зависит от алгоритма планирования потоков, то есть оба потока «спешат» для доступа / изменения данных.

Проблемы часто возникают, когда один поток выполняет «проверку, затем действие» (например, «проверяет», является ли значение X, затем «действует», чтобы сделать что-то, что зависит от значения, равного X), а другой поток что-то делает со значением в между «чеком» и «актом». Например:

if (x == 5) // The "Check"
{
   y = x * 2; // The "Act"

   // If another thread changed x in between "if (x == 5)" and "y = x * 2" above,
   // y will not be equal to 10.
}

Дело в том, что y может быть 10 или что угодно, в зависимости от того, изменил ли другой поток x между проверкой и действием. У вас нет реального способа узнать.

Чтобы предотвратить возникновение условий гонки, вы обычно устанавливаете блокировку общих данных, чтобы гарантировать, что только один поток может получить доступ к данным одновременно. Это будет означать что-то вроде этого:

// Obtain lock for x
if (x == 5)
{
   y = x * 2; // Now, nothing can change x until the lock is released. 
              // Therefore y = 10
}
// release lock for x
person Lehane    schedule 29.08.2008
comment
Что делает другой поток, когда он встречает блокировку? Это подождет? Ошибка? - person Brian Ortiz; 19.10.2009
comment
Да, другой поток должен будет дождаться снятия блокировки, прежде чем он сможет продолжить. Это делает очень важным, чтобы блокировка была снята удерживающей нитью, когда она закончила с ней. Если он никогда не освобождает его, другой поток будет ждать бесконечно. - person Lehane; 22.10.2009
comment
@Ian В многопоточной системе всегда будут моменты, когда ресурсы должны быть разделены. Сказать, что один подход плох, не предлагая альтернативы, просто непродуктивно. Я всегда ищу способы улучшить, и если есть альтернатива, я с удовольствием изучу ее и взвесу все за и против. - person Despertar; 03.05.2012
comment
@Despertar Да, но вы можете спроектировать свою многопоточную систему таким образом, чтобы конкуренция за данные была сведена к минимуму - это альтернатива. Во всяком случае, я не вижу проблемы в том, чтобы кто-то только упомянул проблему с подходом, если они объяснят, в чем проблема. - person Ian Warburton; 03.05.2012
comment
@Despertar ... также, это не обязательно тот случай, когда ресурсы всегда должны быть разделены в многопоточной системе. Например, у вас может быть массив, каждый элемент которого требует обработки. Вы могли бы разделить массив и иметь поток для каждого раздела, и потоки могут выполнять свою работу полностью независимо друг от друга. - person Ian Warburton; 03.05.2012
comment
+1 за напоминание о блокировке переменных, используемых в условии if. На первый взгляд, я бы поставил блокировку только вокруг y, поскольку это изменяемые данные, но в вашем примере это не принесет никакой пользы. - person goku_da_master; 18.10.2012
comment
Для возникновения гонки достаточно, чтобы один поток попытался изменить общие данные, в то время как остальные потоки могут либо прочитать, либо изменить их. - person SomeWittyUsername; 09.11.2012
comment
Но как другой поток получит доступ к этой переменной? Разве это не ограничено по объему (локальная переменная)? - person committedandroider; 07.03.2015
comment
Согласно этому определению, в программах на одном ядре не может быть состояния гонки, потому что потоки мультиплексируются по времени и никогда не выполняются одновременно. Состояние гонки не должно определяться поведением во время выполнения; он должен быть свойством некоторого кода. - person qznc; 15.03.2016
comment
Сужение понятия состояния гонки до несинхронизированного доступа к переменной - очень вводящий в заблуждение способ ответить на исходный вопрос. Условия гонки никоим образом не связаны с доступом к данным. @Baris Kasikci дал очень хорошие ответы на то, каково на самом деле состояние гонки. - person AnT; 20.04.2016
comment
@tsellon также предоставил очень хорошее объяснение того, что такое состояние гонки. Этот ответ с другой стороны ... Ну, да, несинхронизированный доступ к данным является примером состояния гонки, но это настолько конкретный и узкий пример, что использование его в качестве ответа на общий вопрос о состоянии гонки вводит в заблуждение по крайней мере . - person AnT; 20.04.2016
comment
Я думаю, стоит отметить, что состояние гонки будет возникать только в том случае, если хотя бы один конкурирующий поток попытается записать / изменить ресурс. - person FaceBro; 09.07.2016
comment
Я написал в блоге сообщение о состоянии гонки на Голанге: joonas.fi/2017/02/20/ - person joonas.fi; 21.02.2017
comment
так позволь мне угадать? чтобы предотвратить состояние гонки, вы вводите потенциальный тупик ... C.S. Ирония в лучшем виде - person PirateApp; 03.09.2018
comment
Здесь стоит отметить, что если бы x и y были локальными переменными (т. Е. Если бы они были объявлены внутри функции или переданы как параметры), это состояние гонки НЕ возникло бы, потому что каждый поток имел бы свою собственную копию x и y. - person Gaurav B; 12.12.2018
comment
Нельзя ли просто установить значение x для другой переменной в качестве заполнителя? Например, следующий z = x; if(z == 2){ y = z * 2; } - person Isaac; 25.04.2019
comment
вы упомянули Поскольку алгоритм планирования потоков может переключаться между потоками в любое время, что, если алгоритм планирования меняет поток, пока поток все еще находится внутри критической секции и не разблокирует мьютекс. - person simplePerson43; 17.06.2019
comment
Да, и есть проблема взаимоблокировки, которая возникает из-за получения блокировки от разных потоков. - person Mike; 09.08.2019
comment
каков фактический синтаксис для реализации блокировки в C? - person mLstudent33; 31.12.2019
comment
Не уверен, что я просто неправильно это понимаю. Состояние гонки возникает, когда два или более потока могут получить доступ к общим данным и пытаются изменить их одновременно. Я понимаю это как состояние гонки = оба пытаются изменить общие данные одновременно, но на самом деле достаточно, если один из них пишет. Также ваш пример читает только из x (в то время как другой поток записывает в него) - person 463035818_is_not_a_number; 03.12.2020
comment
@BrianOrtiz Просто подожди - person linjiejun; 02.02.2021

«Состояние гонки» возникает, когда многопоточный (или иначе параллельный) код, который обращался бы к общему ресурсу, мог сделать это таким образом, чтобы вызвать неожиданные результаты.

Возьмем этот пример:

for ( int i = 0; i < 10000000; i++ )
{
   x = x + 1; 
}

Если бы у вас было 5 потоков, выполняющих этот код одновременно, значение x НЕ БУДЕТ в конечном итоге равным 50 000 000. Фактически это будет меняться с каждым запуском.

Это потому, что для того, чтобы каждый поток увеличивал значение x, они должны сделать следующее: (упрощенно, очевидно)

Retrieve the value of x
Add 1 to this value
Store this value to x

Любой поток может быть на любом этапе этого процесса в любое время, и они могут наступать друг на друга, когда задействован общий ресурс. Состояние x может быть изменено другим потоком во время между чтением x и его обратной записью.

Допустим, поток получает значение x, но еще не сохранил его. Другой поток также может получить такое же значение x (потому что ни один поток еще не изменил его), и тогда они оба сохранят такое же значение (x + 1) обратно в Икс!

Пример:

Thread 1: reads x, value is 7
Thread 1: add 1 to x, value is now 8
Thread 2: reads x, value is 7
Thread 1: stores 8 in x
Thread 2: adds 1 to x, value is now 8
Thread 2: stores 8 in x

Состояния гонки можно избежать, применив какой-то механизм блокировки перед кодом, который обращается к общему ресурсу:

for ( int i = 0; i < 10000000; i++ )
{
   //lock x
   x = x + 1; 
   //unlock x
}

Здесь каждый раз получается 50 000 000 ответов.

Для получения дополнительной информации о блокировке выполните поиск: мьютекс, семафор, критическая секция, общий ресурс.

person privatehuff    schedule 29.08.2008
comment
См. jakob.engbloms.se/archives/65 для примера программы, чтобы проверить, как лучше такие вещи идут плохо ... это действительно зависит от модели памяти машины, на которой вы работаете. - person jakobengblom2; 12.10.2008
comment
Как он может достичь 50 миллионов, если он должен остановиться на 10 миллионах? - person ; 26.10.2015
comment
@nocomprende: 5 потоков, выполняющих один и тот же код за раз, как описано непосредственно под фрагментом ... - person Jon Skeet; 12.11.2015
comment
@JonSkeet Вы правы, я перепутал i и x. Спасибо. - person ; 12.11.2015
comment
Блокировка с двойной проверкой при реализации шаблона Singleton является таким примером предотвращения состояния гонки. - person Bharat Dodeja; 31.08.2016

Что такое состояние гонки?

Вы планируете пойти в кино в 17:00. Уточняйте наличие билетов в 16.00. Представитель говорит, что они есть в наличии. Вы расслабляетесь и подходите к кассе за 5 минут до спектакля. Уверен, вы догадываетесь, что происходит: аншлаг. Проблема здесь заключалась в продолжительности между проверкой и действием. Вы спросили в 4 и действовали в 5. Тем временем кто-то другой забрал билеты. Это состояние гонки - в частности, сценарий состояния гонки «проверка, затем действие».

Как их обнаружить?

Обзор религиозного кода, многопоточные модульные тесты. Нет никакого ярлыка. Для этого есть несколько плагинов Eclipse, но пока ничего стабильного.

Как вы справляетесь с ними и предотвращаете их?

Лучше всего было бы создавать функции без побочных эффектов и без состояния, как можно больше использовать неизменяемые. Но это не всегда возможно. Так что использование java.util.concurrent.atomic, параллельных структур данных, правильной синхронизации и параллелизма на основе акторов поможет.

Лучший ресурс для параллелизма - JCIP. Вы также можете получить дополнительные подробные сведения о приведенном выше объяснении здесь.

person Vishal Shukla    schedule 04.10.2013
comment
Анализ кода и модульные тесты второстепенны по сравнению с моделированием потока между вашими ушами и меньшим использованием разделяемой памяти. - person Acumenus; 26.11.2013
comment
Я оценил реальный пример состояния гонки - person Tom O.; 06.06.2017
comment
Нравится ответ палец вверх. Решение: вы блокируете билеты между 4-5 мьютексом (взаимное исключение, c ++). В реальности это называется бронированием билетов :) - person Volt; 25.08.2017
comment
был бы достойным ответом, если бы вы отбросили биты только для java (вопрос не о Java, а, скорее, об условиях гонки в целом) - person Corey Goldberg; 26.08.2018
comment
Нет, это не состояние гонки. С точки зрения бизнеса, вы просто слишком долго ждали. Очевидно, что отложенный заказ - это не решение. Попробуйте спекулянт, иначе просто купите билет в качестве страховки. - person csherriff; 03.12.2018
comment
Действительно, отличный ответ: условия гонки возникнут, если мы вообще столкнемся с ситуациями CHECK AND ACT и READ_MODIFY_UPDATE. - person Sumanth Varada; 10.01.2019

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

Гонка данных происходит, когда 2 инструкции обращаются к одному и тому же участку памяти, по крайней мере один из этих обращений является записью, и среди этих обращений не происходит выполнения до упорядочения. Теперь то, что составляет «происходит до упорядочивания», является предметом множества споров, но в целом пары «блокировка-блокировка» для одной и той же переменной блокировки и пары «ожидание-сигнал» для одной и той же переменной условия вызывают порядок «происходит раньше».

Состояние гонки - это семантическая ошибка. Это ошибка, возникающая во времени или порядке событий, которая приводит к ошибочному поведению программы.

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

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

Учитывая, что условия гонки являются семантическими ошибками, не существует общего способа их обнаружения. Это потому, что не существует автоматического оракула, который мог бы отличить правильное поведение программы от неправильного в общем случае. Обнаружение расы - неразрешимая проблема.

С другой стороны, гонки данных имеют точное определение, которое не обязательно связано с правильностью, и поэтому их можно обнаружить. Существует множество разновидностей детекторов гонки данных (статическое / динамическое обнаружение гонки данных, обнаружение гонки данных на основе набора блокировок, обнаружение гонки данных на основе «происходит раньше», обнаружение гибридной гонки данных). Современным детектором динамической гонки данных является ThreadSanitizer, который работает очень хорошо на практике.

Обработка гонок данных в целом требует определенной программной дисциплины, чтобы вызвать границы «происходит раньше» между доступами к общим данным (либо во время разработки, либо после их обнаружения с помощью вышеупомянутых инструментов). это можно сделать с помощью блокировок, переменных состояния, семафоров и т. д. Однако можно также использовать другие парадигмы программирования, такие как передача сообщений (вместо общей памяти), которые позволяют избежать гонки данных по построению.

person Baris Kasikci    schedule 29.08.2013
comment
Разница имеет решающее значение для понимания состояния гонки. Спасибо! - person ProgramCpp; 03.04.2018
comment
Это ошибка, возникающая во времени или порядке событий, которая приводит к ошибочному поведению программы. Идеальное определение! В самом деле, нет никаких оснований предполагать, что события должны происходить в одном экземпляре приложения. Также применимы несколько экземпляров. - person truefusion; 08.07.2020

Типичным каноническим определением является «когда два потока обращаются к одному и тому же месту в памяти в одно и то же время, и по крайней мере один из обращений является записью». В этой ситуации поток «читателя» может получить старое значение или новое значение, в зависимости от того, какой поток «выиграет гонку». Это не всегда ошибочный факт, некоторые очень сложные низкоуровневые алгоритмы делают это специально, но обычно этого следует избегать. @Steve Gury дает хороший пример того, когда это может быть проблемой.

person Chris Conway    schedule 29.08.2008
comment
Не могли бы вы привести пример того, как условия гонки могут быть полезны? Гугл не помог. - person Alex V.; 11.12.2013
comment
@Alex V. На данный момент я понятия не имею, о чем говорю. Я думаю, что это могло быть отсылкой к программированию без блокировок, но не совсем правильно сказать, что это зависит от условий гонки как таковых. - person Chris Conway; 12.12.2013

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

Пример: представьте, что у вас есть два потока, A и B.

В теме A:

if( object.a != 0 )
    object.avg = total / object.a

В потоке B:

object.a = 0

Если поток A вытесняется сразу после проверки того, что object.a не равен нулю, B сделает a = 0, а когда поток A получит процессор, он выполнит «деление на ноль».

Эта ошибка возникает только тогда, когда поток A вытесняется сразу после оператора if, это очень редко, но может произойти.

person Steve Gury    schedule 29.08.2008

Состояние гонки - это ситуация при параллельном программировании, когда два параллельных потока или процесса конкурируют за ресурс, и конечное конечное состояние зависит от того, кто первым получит ресурс.

person Jorge Córdoba    schedule 29.08.2008
comment
просто блестящее объяснение - person gokareless; 09.02.2019
comment
Конечное состояние чего? - person Roman Alexandrovich; 20.06.2019
comment
@RomanAlexandrovich Финальное состояние программы. Состояние, относящееся к таким вещам, как значения переменных и т. Д. См. Отличный ответ Лехана. Состояние в его примере будет относиться к конечным значениям «x» и «y». - person AMTerp; 11.11.2019

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

Согласно wikipedia:

Термин происходит от идеи двух сигналов, участвующих друг в друге, чтобы сначала повлиять на результат.

Состояние гонки в логической схеме:

введите описание изображения здесь

Индустрия программного обеспечения использовала этот термин без изменений, что затрудняет его понимание.

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

  • два сигнала = ›два потока / два процесса
  • влиять на выход = ›влиять на какое-то общее состояние

Таким образом, состояние гонки в индустрии программного обеспечения означает, что два потока / два процесса соревнуются друг с другом, чтобы повлиять на какое-то общее состояние, а конечный результат общего состояния будет зависеть от некоторой тонкой разницы во времени, которая может быть вызвана определенным порядком запуска потока / процесса, планирование потоков / процессов и т. д.

person nybon    schedule 04.08.2017

Условия состязания возникают в многопоточных приложениях или многопроцессорных системах. Состояние гонки, по сути, - это все, что предполагает, что две вещи, находящиеся не в одном потоке или процессе, будут происходить в определенном порядке, без принятия мер, гарантирующих, что это произойдет. Это обычно происходит, когда два потока передают сообщения, устанавливая и проверяя переменные-члены класса, к которым оба имеют доступ. Почти всегда возникает состояние гонки, когда один поток вызывает сон, чтобы дать другому потоку время для завершения задачи (если только этот сон не находится в цикле с каким-либо механизмом проверки).

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

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

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

person tsellon    schedule 29.08.2008

На самом деле Microsoft опубликовала действительно подробную статью по этому вопросу о состояниях гонки и взаимоблокировках. Самым обобщенным отрывком из него будет заголовок:

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

person Konstantin Dinev    schedule 14.09.2012

Что такое состояние гонки?

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

Например, процессору A и процессору B требуется одинаковый ресурс для выполнения.

Как их обнаружить?

Есть инструменты для автоматического определения состояния гонки:

Как вы с ними справляетесь?

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

Как предотвратить их появление?

Существуют различные способы предотвращения состояния гонки, например Избежание критического раздела.

  1. Не может быть двух процессов одновременно внутри своих критических областей. (Взаимное исключение)
  2. Никаких предположений о скорости или количестве процессоров не делается.
  3. Ни один процесс, работающий за пределами своей критической области, блокирует другие процессы.
  4. Ни один процесс не должен бесконечно ждать, чтобы войти в свою критическую область. (A ожидает ресурсов B, B ожидает ресурсов C, C ожидает ресурсов A)
person Adnan Qureshi    schedule 14.11.2014

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

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

person dilbag koundal    schedule 13.04.2012

Вы можете предотвратить состояние гонки, если используете "атомарные" классы. Причина в том, что поток не разделяет операции получения и установки, пример ниже:

AtomicInteger ai = new AtomicInteger(2);
ai.getAndAdd(5);

В результате у вас будет 7 в ссылке "ai". Хотя вы выполнили два действия, но обе операции подтверждают один и тот же поток, и ни один другой поток не будет вмешиваться в это, что означает отсутствие условий гонки!

person Aleksei Moshkov    schedule 12.08.2017

Вот классический пример баланса банковского счета, который поможет новичкам легко понять потоки в Java w.r.t. условия гонки:

public class BankAccount {

/**
 * @param args
 */
int accountNumber;
double accountBalance;

public synchronized boolean Deposit(double amount){
    double newAccountBalance=0;
    if(amount<=0){
        return false;
    }
    else {
        newAccountBalance = accountBalance+amount;
        accountBalance=newAccountBalance;
        return true;
    }

}
public synchronized boolean Withdraw(double amount){
    double newAccountBalance=0;
    if(amount>accountBalance){
        return false;
    }
    else{
        newAccountBalance = accountBalance-amount;
        accountBalance=newAccountBalance;
        return true;
    }
}

public static void main(String[] args) {
    // TODO Auto-generated method stub
    BankAccount b = new BankAccount();
    b.accountBalance=2000;
    System.out.println(b.Withdraw(3000));

}
person realPK    schedule 22.11.2011
comment
по способу депозита, если сумма отрицательная, люди могут внести право - person Parthasarathy B; 28.06.2020

Попробуйте этот базовый пример, чтобы лучше понять состояние гонки:

    public class ThreadRaceCondition {

    /**
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        Account myAccount = new Account(22222222);

        // Expected deposit: 250
        for (int i = 0; i < 50; i++) {
            Transaction t = new Transaction(myAccount,
                    Transaction.TransactionType.DEPOSIT, 5.00);
            t.start();
        }

        // Expected withdrawal: 50
        for (int i = 0; i < 50; i++) {
            Transaction t = new Transaction(myAccount,
                    Transaction.TransactionType.WITHDRAW, 1.00);
            t.start();

        }

        // Temporary sleep to ensure all threads are completed. Don't use in
        // realworld :-)
        Thread.sleep(1000);
        // Expected account balance is 200
        System.out.println("Final Account Balance: "
                + myAccount.getAccountBalance());

    }

}

class Transaction extends Thread {

    public static enum TransactionType {
        DEPOSIT(1), WITHDRAW(2);

        private int value;

        private TransactionType(int value) {
            this.value = value;
        }

        public int getValue() {
            return value;
        }
    };

    private TransactionType transactionType;
    private Account account;
    private double amount;

    /*
     * If transactionType == 1, deposit else if transactionType == 2 withdraw
     */
    public Transaction(Account account, TransactionType transactionType,
            double amount) {
        this.transactionType = transactionType;
        this.account = account;
        this.amount = amount;
    }

    public void run() {
        switch (this.transactionType) {
        case DEPOSIT:
            deposit();
            printBalance();
            break;
        case WITHDRAW:
            withdraw();
            printBalance();
            break;
        default:
            System.out.println("NOT A VALID TRANSACTION");
        }
        ;
    }

    public void deposit() {
        this.account.deposit(this.amount);
    }

    public void withdraw() {
        this.account.withdraw(amount);
    }

    public void printBalance() {
        System.out.println(Thread.currentThread().getName()
                + " : TransactionType: " + this.transactionType + ", Amount: "
                + this.amount);
        System.out.println("Account Balance: "
                + this.account.getAccountBalance());
    }
}

class Account {
    private int accountNumber;
    private double accountBalance;

    public int getAccountNumber() {
        return accountNumber;
    }

    public double getAccountBalance() {
        return accountBalance;
    }

    public Account(int accountNumber) {
        this.accountNumber = accountNumber;
    }

    // If this method is not synchronized, you will see race condition on
    // Remove syncronized keyword to see race condition
    public synchronized boolean deposit(double amount) {
        if (amount < 0) {
            return false;
        } else {
            accountBalance = accountBalance + amount;
            return true;
        }
    }

    // If this method is not synchronized, you will see race condition on
    // Remove syncronized keyword to see race condition
    public synchronized boolean withdraw(double amount) {
        if (amount > accountBalance) {
            return false;
        } else {
            accountBalance = accountBalance - amount;
            return true;
        }
    }
}
person Morsu    schedule 31.05.2013

Не всегда нужно отказываться от состояния гонки. Если у вас есть флаг, который может быть прочитан и записан несколькими потоками, и этот флаг установлен на «готово» одним потоком, чтобы другой поток прекратил обработку, когда флаг установлен на «готово», вы не хотите, чтобы эта «гонка» условие "подлежит устранению. Фактически, это можно назвать доброкачественным состоянием гонки.

Однако при использовании инструмента для определения состояния гонки это будет обнаружено как опасное состояние гонки.

Дополнительные сведения о состоянии гонки см. Здесь, http://msdn.microsoft.com/en-us/magazine/cc546569.aspx.

person kiriloff    schedule 07.09.2014
comment
На каком языке основан ваш ответ? - person MikeMB; 21.04.2015
comment
Откровенно говоря, мне кажется, что если у вас есть условия гонки per se, вы не строите свой код строго контролируемым образом. Что, хотя это может и не быть проблемой в вашем теоретическом случае, свидетельствует о более серьезных проблемах с тем, как вы проектируете и разрабатываете программное обеспечение. Ожидайте, что рано или поздно столкнетесь с болезненными ошибками состояния гонки. - person Engineer; 13.07.2016

Рассмотрим операцию, которая должна отображать счетчик, как только счетчик увеличивается. то есть, как только CounterThread увеличивает значение, DisplayThread должно отобразить последнее обновленное значение.

int i = 0;

Выход

CounterThread -> i = 1  
DisplayThread -> i = 1  
CounterThread -> i = 2  
CounterThread -> i = 3  
CounterThread -> i = 4  
DisplayThread -> i = 4

Здесь CounterThread часто получает блокировку и обновляет значение до того, как его отобразит DisplayThread. Здесь существует состояние гонки. Состояние гонки можно решить с помощью синхронизации

person bharanitharan    schedule 15.07.2015

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

person rashedcs    schedule 05.12.2018