написать впереди
предыдущий постКак с таким количеством общих ресурсов защитить несколько ресурсов с помощью одной блокировки?В статье мы рассказали о классическом случае банковского перевода, в котором есть две проблемы:
- Простое использование синхронизированного метода не защитит цель (не может защитить цель)
- При использовании схемы блокировки Account.class степень детализации блокировки слишком велика, в результате чего все операции, связанные с учетной записью (снятие средств, перевод, изменение пароля и т. д.), станут последовательными операциями.
Как решить эти две проблемы? Давайте сначала переоденемся, отправимся в прошлое, чтобы найти банк, и посмотрим на суть через феномен, дэндэн дэн......
Подойдите к банку и скажите кассиру, что вы хотите перевести 100 медных монет Ти Дану.В это время кассир оборачивается и ищет вашу и Ти Дана книгу на стене.В это время кассир может столкнуться с тремя ситуациями :
- Идеальное состояние: и вы, и бухгалтерская книга Ти Дан'эр находятся в состоянии ожидания, соберите их вместе, вычтите 100 монет из своей бухгалтерской книги, добавьте 100 монет в бухгалтерскую книгу Ти Дэна, и кассир повернет и повесит бухгалтерскую книгу обратно на стену. и все готово.
- Неловкое состояние: Ваша учетная книга находится здесь, а учетная книга Ти Данер взята другими кассирами для перевода денег другим.Вы должны ждать, пока другие кассиры вернут учетную книгу Ти Данер.
- Сумасшедшее состояние: вашей книги нет, как и книги Тиданера, вы можете только ждать, пока обе книги будут возвращены
Замедление работы кассира с учетной книгой.Он должен сначала получить вашу учетную книгу, а затем перейти к учетной книге Латте Дэна.После получения обоих счетов (идеальное состояние) перевод может быть завершен.Используйте программную модель для описания этого процесса. взятия бухгалтерской книги:
Продолжим описание вышеописанной модели программным кодом:
class Account {
private int balance;
// 转账
void transfer(Account target, int amt){
// 锁定转出账户
synchronized(this) {
// 锁定转入账户
synchronized(target) {
if (this.balance > amt) {
this.balance -= amt;
target.balance += amt;
}
}
}
}
}
Это решение выглядит идеальным и решает две проблемы, упомянутые в начале статьи, но так ли это на самом деле?
Идеальное состояние, о котором мы только что сказали, состоит в том, что в банке есть только один кассир (то есть один поток). По мере того, как масштаб банка становится больше, на стене уже висит много бухгалтерских книг.Чтобы справиться с загруженным бизнесом, банк открыл несколько окон.В настоящее время есть несколько кассиров (многопоточных) для обработки банковский бизнес.
Кассир 1 находится в процессе перевода денег Тие Данеру, но получил только вашу учетную книгу; Кассир 2 занимается переводом денег Тие Данеру, но получил только учетную книгу Тие Данер. В настоящее время обе стороны находятся в состоянии смущающее состояние, два кассира ждут, пока другая сторона вернет бухгалтерскую книгу, чтобы обработать перевод бизнеса для текущего клиента.
Наяву кассир будет общаться и выкрикиватьСтарый Галстук, бухгалтерская книга Ти Дан'эр будет использована для меня в первую очередь, и я верну ее вам после использования., но программа не такая шустрая, синхронизированная встроенная блокировка очень настойчивая, она вам правду "мертвого ожидания" скажет, и в итоге происходит взаимоблокировка
Java имеет синхронизированную встроенную блокировку, а также изобрела блокировку дисплея. Это просто для того, чтобы вылечить постоянное «мертвое ожидание» синхронизированного? 😏
решение
Как решить вышеуказанную проблему? Как говорится, познание себя и познание другого может привести к сотне битв. Мы должны сначала понять, какие ситуации приведут к тупикам, прежде чем мы сможем узнать, как их избежать. К счастью, мы можем стоять на плечах гигантов и смотреть на проблемы.
Coffman
Четыре условия суммированы, чтобы указать, что взаимоблокировка может возникнуть:
Состояние Коффмана
** Условие взаимного исключения: ** относится к исключительному использованию выделенных ресурсов процессом, то есть определенный ресурс занят только одним процессом в течение определенного периода времени. Если в это время есть другие процессы, запрашивающие ресурсы, запрашивающая сторона может только ждать, пока процесс, занимающий ресурсы, не будет израсходован и освобожден.
**Условия запроса и удержания: **означает, что процесс сохранил хотя бы один ресурс, но был сделан новый запрос ресурса, и ресурс был занят другими процессами.В это время запрашивающий процесс заблокирован, но у него также есть другие ресурсы, которые он получил.
**Неотъемлемое условие: **Относится к ресурсам, полученным процессом, которые не могут быть лишены до того, как они будут израсходованы, и могут быть высвобождены только сами по себе, когда они будут израсходованы.
** Циклическое условие ожидания: ** означает, что при возникновении взаимоблокировки должна быть кольцевая цепочка процесс-ресурс, то есть P1 в наборе процессов {P1, P2, ..., Pn} ожидает занятого процесса P2.Resource, P2 ожидает ресурс, занятый P3, ..., Pn ожидает ресурс, уже занятый P0.
Эти условия хорошо понятны, среди них «условие взаимного исключения» является основой параллельного программирования, и это условие нельзя изменить. Но другие три условия могут измениться, то есть, если другие три условия будут нарушены, проблема взаимоблокировки, упомянутая выше, не возникнет.
запрос на прерывание и условие удержания
Каждый кассир может взять и поставить гроссбух, и легко ждать друг друга. Чтобы прервать запрос и удержать условие, вам нужно получить все ресурсы сразу.
Как программист, вы наверняка слышали это предложение:
Любые проблемы разработки программного обеспечения можно решить, добавив промежуточный слой.
Мы не разрешаем кассирам брать и размещать реестр, и реестр должен управляться отдельным администратором реестра.
Другими словами, администратор учетной книги считает, что учетная книга является критической областью.Если получена только одна из учетных книг, она не будет передана кассиру, а будет ждать, пока кассир спросит в следующий раз, обе ли счета есть.
//账本管理员
public class AccountBookManager {
synchronized boolean getAllRequiredAccountBook( Object from, Object to){
if(拿到所有账本){
return true;
} else{
return false;
}
}
// 归还资源
synchronized void releaseObtainedAccountBook(Object from, Object to){
归还获取到的账本
}
}
public class Account {
//单例的账本管理员
private AccountBookManager accountBookManager;
public void transfer(Account target, int amt){
// 一次性申请转出账户和转入账户,直到成功
while(!accountBookManager.getAllRequiredAccountBook(this, target)){
return;
}
try{
// 锁定转出账户
synchronized(this){
// 锁定转入账户
synchronized(target){
if (this.balance > amt){
this.balance -= amt;
target.balance += amt;
}
}
}
} finally {
accountBookManager.releaseObtainedAccountBook(this, target);
}
}
}
нарушить неотъемлемое условие
Вышеизложенное дало вам небольшую подсказку: чтобы решить проблему сохранения встроенных блокировок, экранные блокировки Java поддерживают уведомление (notify/notifyall) и ожидание (wait), что означает, что эта функция может быть достигнута с помощью крика.Старый Галстук, бухгалтерская книга Ти Дан'эр будет использована для меня в первую очередь, и я верну ее вам после использования.Функция этого будет объяснена позже, когда дело доходит до соответствующего содержимого Java SDK.
прерывание цикла ожидания
Также очень просто разрушить условие ожидания цикла, нам нужно только отсортировать и получить размер порядкового номера ресурса, чтобы решить эту проблему и удалить цикл.
Продолжайте иллюстрировать код:
class Account {
private int id;
private int balance;
// 转账
void transfer(Account target, int amt){
Account smaller = this
Account larger = target;
// 排序
if (this.id > target.id) {
smaller = target;
larger = this;
}
// 锁定序号小的账户
synchronized(smaller){
// 锁定序号大的账户
synchronized(larger){
if (this.balance > amt){
this.balance -= amt;
target.balance += amt;
}
}
}
}
}
Когда меньший поток занят, другие потоки будут заблокированы, и взаимной блокировки не будет.
Дополнительная информация
В реальном бизнесе учетная запись будет объектом базы данных, и мы можем решить ее с помощью транзакций или оптимистичной блокировки базы данных. Кроме того, в распределенной системе обработка роли менеджера по учетным записям также может быть решена с помощью распределенных блокировок redis.
При работе с запросами на уничтожение и условиями удержания мы используем метод цикла while для непрерывного запроса блокировок.В реальном бизнесе у нас есть настройки времени ожидания, чтобы предотвратить бесконечную трату ресурсов ЦП.
Кроме того, вы можете попробовать использовать инструмент Ali с открытым исходным кодом Arthas для проверки использования ЦП, потоков и других связанных с этим проблем, на github есть четкие инструкции.
Суммировать
Вычислительная мощность компьютера намного превосходит человеческую, но его интеллект все еще нуждается в улучшении.Глядя на параллелизм, мы часто думаем, что самый простой коммуникационный компьютер людей может это сделать.На самом деле это не так. ., посмотреть на проблему с точки зрения компьютера
Мы не выступаем за крупнозернистые блокировки, поэтому будем использовать мелкозернистые блокировки, но при использовании мелкозернистых замков мы должны строго следовать четырем условиям Коффмана, чтобы судить одно за другим, а затем применять наши решения для их решения.
вопрос души
- Когда условия запроса и удержания отменены, узким местом вычислительной мощности является менеджер аккаунта. Как вы думаете, этот метод обработки увеличит количество параллелизма?
- Способ сломать условие удержания запроса и способ сломать цикл ожидания, как вы думаете, какой способ лучше
- Что произойдет при нарушении условий запроса и удержания, если код будет выглядеть следующим образом?
public void transfer(Account target, int amt){
// 一次性申请转出账户和转入账户,直到成功
while(accountBookManager.getAllRequiredAccountBook(this, target)){}
try{
// 锁定转出账户
synchronized(this){
// 锁定转入账户
synchronized(target){
if (this.balance > amt){
this.balance -= amt;
target.balance += amt;
}
}
}
} finally {
accountBookManager.releaseObtainedAccountBook(this, target);
}
}
}
инструменты повышения производительности
- На этот раз в мир параллелизма, пожалуйста, не пропустите
- Чтобы научиться параллельному программированию, необходимо глубокое понимание этих трех основных элементов.
- Есть три источника одновременных ошибок, пожалуйста, следите за ними.
- Наглядность и упорядоченность, Бывает-прежде чем это сделать
- Решить проблему атомарности? Что вам нужно в первую очередь, так это понимание макросов
- О чем следует говорить при опросе одновременных изменчивых ключевых слов?
Добро пожаловать, чтобы продолжать обращать внимание на общественный номер: «Сун Гун И Бин».
- Передовая технология Java для обмена галантереей
- Резюме эффективных инструментов | Ответ на «Инструменты»
- Анализ вопроса интервью и ответ
- Сбор технических данных | Ответ на «данные»
Узнайте о стеке технологий Java легко и весело, думая о чтении детективных романов, и постепенно разлагайте технические проблемы, основываясь на принципах упрощения сложных проблем, конкретизации абстрактных проблем и графики.Технология постоянно обновляется, пожалуйста, продолжайте платить внимание...