Synchronized Decorators to Replace Thread-Safe Classes

The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:

Вы знаете, что такое потокобезопасность, верно? Если нет, ниже приведен простой пример. Все классы должны быть потокобезопасными, верно? На самом деле нет. Некоторые из них должны быть потокобезопасными? И снова неправильно. Я думаю, что ни один из них не должен быть потокобезопасным, в то время как все они должны предоставлять синхронизированные декораторы.

Давайте начнем с примера (кстати, он изменяемый):

Что вы думаете — является ли это потокобезопасным? Этот термин относится к тому, будет ли объект этого класса работать без ошибок при использовании несколькими потоками одновременно. Допустим, у нас есть два потока, работающих с одним и тем же объектом position и вызывающих его метод increment() в точно одинаковый момент времени.

Мы ожидаем, что значение целого числа number будет равно 2, когда оба потока закончат свою работу, потому что каждый из них увеличит его один раз, верно? Однако, скорее всего, это не произойдет.

Давайте посмотрим, что произойдет. В обоих потоках значение before будет равно 0 при их запуске. Затем значение after будет установлено в 1. Затем оба потока выполнят this.number = 1, и вместо ожидаемого значения 2 мы получим 1 в переменной number. Видите проблему? Классы с такими недостатками в своем проектировании не являются потокобезопасными.

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

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

Теперь вопрос: нужно ли делать все классы потокобезопасными или только некоторые из них? Кажется, лучше иметь все классы без ошибок, не так ли? Зачем кому-то объект, который может сломаться в какой-то момент? Ну, не совсем так. Помните, здесь есть проблема производительности; у нас не всегда есть несколько потоков, и мы всегда хотим, чтобы наши объекты работали максимально быстро. Механизм синхронизации между потоками обязательно замедлит нас.

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

Теперь, когда нам требуется, чтобы наш объект position был потокобезопасным, мы декорируем его с помощью SyncPosition.

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

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

Кстати, эта проблема очень близка к проблеме защитного программирования и валидаторов.

Translated by ChatGPT gpt-3.5-turbo/42 on 2023-12-27 at 10:38

sixnines availability badge   GitHub stars