Содержание
- 1 Почему происходит гонка в Java?
- 2 Давайте посмотрим на логику программы ниже:
- 3 CrunchifyRaceCondition.java
- 4 CrunchifyTransaction.java
- 5 CrunchifyBankAccount.java
- 6 Теперь удалите синхронизированное ключевое слово из строк 24 и 34 и запустите ту же программу.
- 7 Теперь вопрос, как избежать Race Condition в вашем Java-приложении?
Некоторое время назад я написал статью о Producer Consumer Example и о том, как лучше обрабатывать операции чтения / записи в Java. На аналогичной ноте, в этом уроке мы обсудим что-то Race Condition а также Thread locking ,
Если у вас есть какие-либо из приведенных ниже вопросов, то вы попали по адресу:
- Пример состояния гонки Java
- пример мьютекса Java
- многопоточность — что такое состояние гонки?
- Расовые условия и критические секции
- Что такое состояние гонки?
- Как бороться с условием гонки в Java на примере
Почему происходит гонка в Java?
Состояние гонки в Java возникает, когда two or more threads попытаться изменить / обновить общие данные на same time ,
Давайте посмотрим на логику программы ниже:
Это очень простой банковский пример, в котором вы будете
depositа такжеwithdrawсуммы100 times, Вы внесете 100 долларов в сумме 100 раз = 100 х 100 = 10000 долларов, и вы снимите 50 долларов всего 100 раз = 50 х 100 = 5000 долларов. По окончании программы у вас должно быть 5000 долларов в вашем банке.
Вот шаги:
- Создать класс CrunchifyRaceCondition.java
- Создать класс CrunchifyTransaction.java
- Создать класс CrunchifyBankAccount.java
- Мы запустим класс CrunchifyRaceCondition и он запустит цикл ввода-вывода 100 раз.
- Мы его запустим
with Synchronized blockпроверить результат - Мы его запустим
without Synchronized blockпроверить результат
CrunchifyRaceCondition.java
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
пакет ком . crunchify. учебник ;
/ **
* @author Crunchify.com
*
* /
общественности учебный класс CrunchifyRaceCondition {
общественности статический недействительным main ( Строка [ ] аргументы ) {
CrunchifyBankAccount crunchifyAccount знак равно новый CrunchifyBankAccount ( CrunchifyAccountNumber ) ;
// Общая ожидаемая сумма депозита: 10000 (100 x 100)
за ( int я знак равно 0 ; я < 100 ; я ++ ) {
CrunchifyTransaction T знак равно новый CrunchifyTransaction ( crunchifyAccount , CrunchifyTransaction . TransactionType . DEPOSIT_MONEY , 100 ) ;
т . начало ( ) ;
}
// Общее ожидаемое снятие: 5000 (100 x 50)
за ( int я знак равно 0 ; я < 100 ; я ++ ) {
CrunchifyTransaction T знак равно новый CrunchifyTransaction ( crunchifyAccount , CrunchifyTransaction . TransactionType . WITHDRAW_MONEY , 50 ) ;
т . начало ( ) ;
}
// Давайте подождем секунду, чтобы убедиться, что выполнение всех потоков завершено.
пытаться {
Thread. сон ( 1000 ) ;
} ловить ( InterruptedException е ) {
Система. вне. println ( e ) ;
}
// Ожидаемый остаток на счете 5000
Система. вне. println ( «Окончательный баланс счета:» + crunchifyAccount . getAccountBalance ( ) ) ;
}
}
|
CrunchifyTransaction.java
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
пакет ком . crunchify. учебник ;
/ **
* @author Crunchify.com
* /
учебный класс CrunchifyTransaction продолжается Нить {
общественности статический перечисление Тип операции {
DEPOSIT_MONEY ( 1 ) , WITHDRAW_MONEY ( 2 ) ;
частный TransactionType ( int ценность ) {
}
} ;
частный TransactionType transactionType;
частный CrunchifyBankAccount crunchifyAccount ;
частный двойной crunchifyAmount ;
/ *
* Если TransactionsType == 1, depositAmount (), в противном случае, если TransactionsType == 2 изъятьAmount ().
* /
общественности CrunchifyTransaction ( CrunchifyBankAccount crunchifyAccount , TransactionType transactionType, двойной crunchifyAmount ) {
это. Тип операции знак равно actionType ;
это. crunchifyAccount знак равно crunchifyAccount ;
это. crunchifyAmount знак равно crunchifyAmount ;
}
общественности недействительным запустить ( ) {
переключатель (Это. TransactionType) {
дело DEPOSIT_MONEY :
depositAmount ( ) ;
printBalance ( ) ;
перерыв ;
дело WITHDRAW_MONEY :
изъять сумму ( ) ;
printBalance ( ) ;
перерыв ;
по умолчанию :
Система. вне. println ( «НЕ ДЕЙСТВИТЕЛЬНАЯ СДЕЛКА» ) ;
}
}
общественности недействительным depositAmount ( ) {
это. crunchifyAccount . depositAmount ( this . crunchifyAmount ) ;
}
общественности недействительным изъять сумму ( ) {
это. crunchifyAccount . изъять сумму ( crunchifyAmount ) ;
}
общественности недействительным printBalance ( ) {
Система. вне. println ( Thread . currentThread ( ) . getName ( ) + : Тип операции: + это. Тип операции + , Количество: + это. crunchifyAmount ) ;
Система. вне. println ( «Баланс нового счета:» + это. crunchifyAccount . getAccountBalance ( ) ) ;
}
}
|
CrunchifyBankAccount.java
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
пакет ком . crunchify. учебник ;
/ **
* @author Crunchify.com
* /
учебный класс CrunchifyBankAccount {
частный строка crunchifyAccountNumber ;
частный двойной crunchifyAccountBalance ;
общественности строка getAccountNumber ( ) {
вернуть crunchifyAccountNumber ;
}
общественности двойной getAccountBalance ( ) {
вернуть crunchifyAccountBalance ;
}
общественности CrunchifyBankAccount ( String crunchifyAccountNumber ) {
это. crunchifyAccountNumber знак равно crunchifyAccountNumber ;
}
// Запишите эту строку — добавлено синхронизированное ключевое слово
общественности синхронизированный логический depositAmount ( двойной сумма ) {
если ( сумма < 0 ) {
вернуть ложь ;
} еще {
crunchifyAccountBalance знак равно crunchifyAccountBalance + количество ;
вернуть правда ;
}
}
// Запишите эту строку — добавлено синхронизированное ключевое слово
общественности синхронизированный логический изъять сумму ( двойной сумма ) {
если ( сумма > crunchifyAccountBalance ) {
вернуть ложь ;
} еще {
crunchifyAccountBalance знак равно crunchifyAccountBalance — количество ;
вернуть правда ;
}
}
}
|
Пожалуйста, проверьте строки 24 и 34 выше. Держи это Synchronized Ключевое слово и запустить вашу программу . Вы должны увидеть правильный результат, как вы видите его на рисунке ниже.
Теперь удалите синхронизированное ключевое слово из строк 24 и 34 и запустите ту же программу.
Вам может потребоваться запустить эту программу несколько раз, чтобы увидеть проблему. В Java нет гарантии, что вы будете постоянно видеть состояние гонки.
Если у вас есть приложение корпоративного уровня, и вы говорите о миллионах транзакций в секунду, то состояние гонки может привести к катастрофе для вашей компании.
Теперь вопрос, как избежать Race Condition в вашем Java-приложении?
- Если условие гонки заключается в обновлениях некоторых общих структур данных в памяти , необходимо синхронизировать доступ и обновления к структуре данных соответствующим образом.
- Если условие гонки находится в обновлениях вашей базы данных, вам необходимо реструктурировать SQL, чтобы использовать транзакции на соответствующем уровне детализации.
- Неплохая идея сделать нагрузочное тестирование перед началом работы в производстве. Большая нагрузка может вызвать редкое состояние гонки. Лучше исправить это прежде, чем исправить это позже.
- Убедитесь, что у вас нет глобальной переменной, в которую вы пишете.
- В Java каждый объект имеет один и только один монитор и мьютекс, связанный с ним. Один монитор имеет несколько дверей, каждая из которых обозначена
synchronizedключевое слово. Когда поток проходит надsynchronizedКлючевое слово, оно эффективно запирает все двери. - Конечно, если поток не проходит через
synchronizedКлючевое слово, оно не заперло дверь, и некоторые другие темы могут в любое время бесплатно войти в баржу.
0.00 (0%) 0 votes








