Лучшие способы записать метод, который обновляет два объекта в многопоточной среде Java?

Предположим, что у нас есть класс под названием AccountService, который управляет состоянием учетных записей.

AccountService определяется как

interface AccountService{
 public void debit(account);
 public void credit(account);
 public void transfer(Account account, Account account1);

}

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

Я интересуюсь ответами, что ссылочный код Java 1.4, а также ответы, которые могли бы использовать ресурсы от java.util.concurrent в Java 5

6
задан mtpettyp 2 June 2010 в 16:49
поделиться

5 ответов

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

Если вы не упорядочите счета, то возникнет вероятность тупика, если один поток будет переходить от A к B, а другой - от B к A.

Этот точный пример обсуждается на странице 207 книги Java Concurrency in Practice, крайне важной для всех, кто занимается многопоточной разработкой на Java. Код примера доступен на сайте издательства:

11
ответ дан 8 December 2019 в 13:44
поделиться

Не могли бы вы избежать синхронизации, используя AtomicReference для баланса аккаунта вместе с get () и set () ?

0
ответ дан 8 December 2019 в 13:44
поделиться

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

Если другие методы также могут получить доступ к AccountService, тогда вы можете решить, чтобы все они использовали одну глобальную блокировку. Самый простой способ сделать это - заключить весь код, который обращается к AccountService, блоком synchronized (X) {...}, где X - это некоторый экземпляр общего / одноэлементного объекта (который может быть самим экземпляром AccountService). Это будет потокобезопасным, потому что только один поток будет обращаться к AccountService одновременно, даже если они находятся в разных методах.

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

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

1
ответ дан 8 December 2019 в 13:44
поделиться

Классический пример, очень хорошо объясненный здесь - http://www.javaworld.com/javaworld/jw-10-2001/jw-1012-deadlock.html?page=4

3
ответ дан 8 December 2019 в 13:44
поделиться

Возможно, вам потребуется полная поддержка транзакций (если, конечно, это настоящее приложение).

Сложность решения практически не зависит от вашего окружения. Подробно опишите вашу систему, и мы постараемся вам помочь (какое приложение? Оно использует веб-сервер? Какой веб-сервер? Что используется для хранения данных? И т. Д.)

2
ответ дан 8 December 2019 в 13:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: