Java: что такое потокобезопасность?

потокобезопасность в Java
Антон Меринов

Антон Меринов

Автор статьи. Интересы, навыки: Профессиональное администрирование СУБД Oracle Database, веб-разработка, IT-World. Подробнее.

 
 
 

Дать определение потокобезопасности в Java непросто. Быстрый поиск в Google выдает многочисленные варианты, подобные этим:

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

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

Учитывая подобные определения, неудивительно, что мы находим потокобезопасность запутанной! Как отличить потокобезопасный класс от небезопасного? Что мы вообще подразумеваем под словом «безопасный»? В основе любого разумного определения потокобезопасности лежит понятие правильности (correctness).

Правильность подразумевает соответствие класса своей спецификации. Спецификация определяет инварианты (invariants), ограничивающие состояние объекта, и постусловия (postconditions), описывающие эффекты от операций. Как узнать, что спецификации для классов являются правильными? Никак, но это не мешает нам их использовать после того, как мы убедили себя, что код работает. Поэтому давайте допустим, что однопоточная правильность — это нечто видимое. Теперь можно предположить, что потокобезопасный класс ведет себя правильно во время доступа из многочисленных потоков.

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

Многопоточная программа не может быть потокобезопасной, если она не является правильной даже в однопоточной среде13. Если объект реализован правильно, то никакая последовательность операций — обращения к публичным методам и чтение или запись в публичные поля — не должна нарушать его инварианты или постусловия. Ни один набор операций, выполняемых последовательно либо конкурентно на экземплярах потокобезопасного класса, не может побудить экземпляр находиться в недопустимом состоянии.

Потокобезопасные классы инкапсулируют любую необходимую синхронизацию сами и не нуждаются в помощи клиента.

Пример: сервлет без поддержки внутреннего состояния

В главе 1 мы перечислили структуры, которые создают потоки и вызывают из них компоненты, за потокобезопасность которых ответственны вы. Теперь мы намерены разработать сервлетную службу разложения на множители и постепенно расширить ее функционал, сохраняя потокобезопасность.

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

Листинг 1. Сервлет без поддержки внутреннего состояния

 

@ThreadSafe
   public class StatelessFactorizer implements Servlet {
      public void service(ServletRequest req, ServletResponse resp) {
         BigInteger i = extractFromRequest(req);
         BigInteger[] factors = factor(i);
         encodeIntoResponse(resp, factors);
   }
}

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

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

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

Вас заинтересует / Intresting for you:

Распространенные заблуждения о...
Распространенные заблуждения о... 2499 просмотров Ирина Светлова Thu, 21 Jun 2018, 18:35:12
Использование потоков в Java
Использование потоков в Java 1468 просмотров Antoni Wed, 12 May 2021, 09:51:36
Аплеты Java и Интернет
Аплеты Java и Интернет 2651 просмотров Ирина Светлова Sat, 09 Jun 2018, 10:17:34
Выбор среды для разработки код...
Выбор среды для разработки код... 2549 просмотров Stas Belkov Sun, 10 Jun 2018, 14:21:35
Войдите чтобы комментировать