Домой Учебники по Java и J2EE Заметили ли вы условия гонки в примере многопоточного параллелизма Java? Как с...

Заметили ли вы условия гонки в примере многопоточного параллелизма Java? Как с этим бороться?

675
0

Некоторое время назад я написал статью о 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 долларов в вашем банке.

Вот шаги:

  1. Создать класс CrunchifyRaceCondition.java
  2. Создать класс CrunchifyTransaction.java
  3. Создать класс CrunchifyBankAccount.java
  4. Мы запустим класс CrunchifyRaceCondition и он запустит цикл ввода-вывода 100 раз.
  5. Мы его запустим with Synchronized block проверить результат
  6. Мы его запустим without Synchronized block проверить результат

CrunchifyRaceCondition.java

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

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

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 Ключевое слово и запустить вашу программу . Вы должны увидеть правильный результат, как вы видите его на рисунке ниже.

ЧИТАТЬ ТАКЖЕ:  Как запускать несколько потоков одновременно в Java? Подход ExecutorService

Теперь удалите синхронизированное ключевое слово из строк 24 и 34 и запустите ту же программу.

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

Если у вас есть приложение корпоративного уровня, и вы говорите о миллионах транзакций в секунду, то состояние гонки может привести к катастрофе для вашей компании.

Теперь вопрос, как избежать Race Condition в вашем Java-приложении?

  1. Если условие гонки заключается в обновлениях некоторых общих структур данных в памяти , необходимо синхронизировать доступ и обновления к структуре данных соответствующим образом.
  2. Если условие гонки находится в обновлениях вашей базы данных, вам необходимо реструктурировать SQL, чтобы использовать транзакции на соответствующем уровне детализации.
  3. Неплохая идея сделать нагрузочное тестирование перед началом работы в производстве. Большая нагрузка может вызвать редкое состояние гонки. Лучше исправить это прежде, чем исправить это позже.
  4. Убедитесь, что у вас нет глобальной переменной, в которую вы пишете.
  5. В Java каждый объект имеет один и только один монитор и мьютекс, связанный с ним. Один монитор имеет несколько дверей, каждая из которых обозначена synchronized ключевое слово. Когда поток проходит над synchronized Ключевое слово, оно эффективно запирает все двери.
  6. Конечно, если поток не проходит через synchronized Ключевое слово, оно не заперло дверь, и некоторые другие темы могут в любое время бесплатно войти в баржу.
Заметили ли вы условия гонки в примере многопоточного параллелизма Java? Как с этим бороться?

0.00 (0%) 0 votes

ОСТАВЬТЕ ОТВЕТ

Пожалуйста, введите ваш комментарий!
пожалуйста, введите ваше имя здесь