Форум программистов, компьютерный форум, киберфорум
Java SE (J2SE)
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.69/26: Рейтинг темы: голосов - 26, средняя оценка - 4.69
-13 / 6 / 6
Регистрация: 04.08.2015
Сообщений: 622

Потокобезопасная реализация метода в репозитории

10.06.2021, 07:59. Показов 5889. Ответов 43
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Имеется класс типа
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Meal {
    private int id;
    private LocalDateTime dateTime;
    private String description;
    private int calories;
 
    public Meal(LocalDateTime dateTime, String description, int calories) {
        this.dateTime = dateTime;
        this.description = description;
        this.calories = calories;
    }
 
    public int getId() {
        return id;
    }
 
    public void setId(int id) {
        this.id = id;
    }
...
Имеется репозиторий для CRUD операций с данными в памяти на сервлете
Java
1
2
3
4
5
6
7
8
9
...
    private AtomicInteger mealAtomicId = new AtomicInteger(0);
 
    @Override
    public void create(Meal meal) {
            meal.setId(mealAtomicId.incrementAndGet());
            MealDb.getMealMap().put(meal.getId(), meal);
    }
...
Утверждается что операция create является не потокобезопасной поскольку другой какой-то поток может инкрементировать mealAtomicId прежде чем будет put(meal.getId(), meal)
Вопросы:
1. Правильное-ли такое утверждение?
2. Если да то как сделать операцию потокобезопасной?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
10.06.2021, 07:59
Ответы с готовыми решениями:

Написание метода поиска объекта для в Jpa репозитории по заранее неизвестному числу параметров
Доброго всем времени суток. Стоит такая задача. Необходимо сделать поиск объекта класса-сущности Worker по комбинации трех параметров:...

Нужно перевести программу из паскаль в делфи . Сама программа этот реализация метода гауса и метода зейделя
Это все в паскале сделано. В программе идет в начале описание меня а аотом сама подпрограмма реализации этих методов. В делфи надо сделать...

Программная реализация "Метода ветвей и границ" или "Метода Гомори"
Здравствуйте. Подскажите, пожалуйста, где можно скачать библиотеки, реализующие какой-нибудь из этих методов? Добавлено через 1 час 16...

43
3584 / 2184 / 571
Регистрация: 02.09.2015
Сообщений: 5,510
11.06.2021, 13:19
Студворк — интернет-сервис помощи студентам
Tavashi, смотри:
Java
1
2
3
4
5
6
7
8
@Override
public void create(Meal meal) {     // 2 треда вызывают данный метод с одним meal
    final var id = mealAtomicId.incrementAndGet();  // thread1: id == 1, thread2: id == 2
    meal.setId(id);     // meal.id == 1 or meal.id == 2 (???)
    final var mealMap = MealDb.getMealMap();    // Дальше можно не продолжать...
    final var newId = meal.getId();
    mealMap.put(newId, meal);
}
Если сможешь, объясни, пожалуйста, "буйному" korvin_, зачем здесь нужны локи (или хотя бы synchronized).
0
 Аватар для Tavashi
1172 / 762 / 194
Регистрация: 21.05.2016
Сообщений: 1,858
11.06.2021, 14:49
Arsegg, что объяснить? Твою мифологию? Попробуй ты сначала привести работающий пример с RC, где ты считаешь будет проблемный код.
0
3584 / 2184 / 571
Регистрация: 02.09.2015
Сообщений: 5,510
11.06.2021, 15:16
Tavashi,
Цитата Сообщение от Arsegg Посмотреть сообщение
meal.setId(id); // meal.id == 1 or meal.id == 2 (???)
Чему будет равен meal.id после вызова двумя потоками данного метода на одном meal:
1) 1;
2) 2;
3) Свой вариант?
0
Эксперт Java
3639 / 2971 / 918
Регистрация: 05.07.2013
Сообщений: 14,220
11.06.2021, 15:22
у одного потока 2, а у другого 1?

Добавлено через 50 секунд
Цитата Сообщение от Arsegg Посмотреть сообщение
на одном meal
как бы не предполагается вызывать их на одном meal
0
3584 / 2184 / 571
Регистрация: 02.09.2015
Сообщений: 5,510
11.06.2021, 15:31
Цитата Сообщение от xoraxax Посмотреть сообщение
как бы не предполагается вызывать их на одном meal
Не увидел ни одного упоминания, почему нельзя.
Цитата Сообщение от xoraxax Посмотреть сообщение
у одного потока 2, а у другого 1?
Правильный ответ: что угодно. В каких-то случаях будет 1, в других - 2.
А если Meal.id был бы типа long/double результаты могли бы получиться куда интереснее.
0
-13 / 6 / 6
Регистрация: 04.08.2015
Сообщений: 622
11.06.2021, 19:38  [ТС]
Предлагается примерно такое решение.
Java
1
2
3
4
5
6
7
8
9
10
@Override
    public Meal create(Meal meal) {
        if (meal.isNew()) {
            meal.setId(mealAtomicId.incrementAndGet());
            MealDb.getMealMap().put(meal.getId(), meal);
            return meal;
    }
        }
        return MealDb.getMealMap().computeIfPresent(meal.getId(), (id, oldMeal) -> meal);
    }
Поясните пожалуйста кому не лень, что тут происходит.
0
Эксперт функциональных языков программированияЭксперт Java
 Аватар для korvin_
4576 / 2775 / 491
Регистрация: 28.04.2012
Сообщений: 8,782
11.06.2021, 23:35
Цитата Сообщение от Arsegg Посмотреть сообщение
// 2 треда вызывают данный метод с одним meal
1) Ты, видимо, совсем не знаком с кодом любого HTTP/API-сервиса на Java, раз не понимаешь, что этот метод не будет вызываться с одним и тем же объектом в разных потоках.
2) Добавляем сюда третий поток, который не вызывает данный метод, но изменяет тот же объект Meal. А теперь расскажи нам, как локи или synchronized в create-методе помогут защититься от некорректного поведения.

Добавлено через 4 минуты
Цитата Сообщение от VlGuvin Посмотреть сообщение
Предлагается примерно такое решение.
Решение чего? Проблем потокобезопасности? Это не решение.

Цитата Сообщение от VlGuvin Посмотреть сообщение
Поясните пожалуйста кому не лень, что тут происходит.
Да практически то же самое, что и в базовом варианте, только зачем-то добавили проверку isNew и вот тут херню сделали:
Java
1
getMealMap().computeIfPresent(meal.getId(), (id, oldMeal) -> meal);
create должен добавлять объект, а не менять существующий, а тут изменение существующего. Правильно так:
Java
1
getMealMap().putIfAbsent(meal.getId(), meal);
0
3584 / 2184 / 571
Регистрация: 02.09.2015
Сообщений: 5,510
12.06.2021, 00:28
Цитата Сообщение от korvin_ Посмотреть сообщение
Ты, видимо, совсем не знаком с кодом любого HTTP/API-сервиса на Java
Как скажешь.
Цитата Сообщение от korvin_ Посмотреть сообщение
что этот метод не будет вызываться с одним и тем же объектом в разных потоках.
Где гарантия?
Цитата Сообщение от korvin_ Посмотреть сообщение
А теперь расскажи нам, как локи или synchronized в create-методе помогут защититься от некорректного поведения.
Давай лучше ты нам расскажешь, как повторишь мат. часть. Ок?
Цитата Сообщение от korvin_ Посмотреть сообщение
create должен добавлять объект, а не менять существующий, а тут изменение существующего.
Переименуй метод в save/store - сути того, что он не thread-safe, не поменяет...
0
 Аватар для Tavashi
1172 / 762 / 194
Регистрация: 21.05.2016
Сообщений: 1,858
12.06.2021, 00:46
Цитата Сообщение от Arsegg Посмотреть сообщение
Ок?
Не ок. Рассказывай все что знаешь. Желательно с полностью рабочим примерчиком.
В конце концов бремя доказательства лежит на тебе.
0
Эксперт функциональных языков программированияЭксперт Java
 Аватар для korvin_
4576 / 2775 / 491
Регистрация: 28.04.2012
Сообщений: 8,782
12.06.2021, 05:28
Цитата Сообщение от Arsegg Посмотреть сообщение
Где гарантия?
В коде.

Цитата Сообщение от Arsegg Посмотреть сообщение
Давай лучше ты нам расскажешь, как повторишь мат. часть. Ок?
Т.е. ты рассказать не можешь. Так я и думал.

Цитата Сообщение от Arsegg Посмотреть сообщение
Переименуй метод в save/store - сути того, что он не thread-safe, не поменяет...
Это вообще к чему?
0
3584 / 2184 / 571
Регистрация: 02.09.2015
Сообщений: 5,510
12.06.2021, 12:07
Цитата Сообщение от korvin_ Посмотреть сообщение
В коде.
Гарантия в коде будет только в таком виде:
Java
1
2
3
4
5
6
7
@Override
public void create(Meal meal) {
    synchronized(meal) {
        meal.setId(mealAtomicId.incrementAndGet());
        MealDb.getMealMap().put(meal.getId(), meal);
    }
}
Все остальное от лукавого и называется одним словом: "Веб-былдлокодинг".
P. S. Как подучишь мат. часть - приходи. Расскажешь нам, как провернуть аналогичный функционал на Lock'ах: ReentrantLock, ReadWriteLock и прочих. Ты же у нас "эксперт".
0
Эксперт функциональных языков программированияЭксперт Java
 Аватар для korvin_
4576 / 2775 / 491
Регистрация: 28.04.2012
Сообщений: 8,782
12.06.2021, 15:25
Цитата Сообщение от Arsegg Посмотреть сообщение
Гарантия в коде будет только в таком виде
И где тут гарантия? Что мне помешает в другом потоке не лочиться на объекте meal и модифицировать ему id?
Садись, два.

Цитата Сообщение от Arsegg Посмотреть сообщение
Как подучишь мат. часть
Это тебе стоит сделать.

Добавлено через 10 минут
Цитата Сообщение от Arsegg Посмотреть сообщение
Гарантия в коде будет только в таком виде:
Даже IDEA подсказывает:

Synchronization on a local variable or method parameter.

Reports synchronization on a local variable or parameter. It is very difficult to guarantee correctness when such synchronization is used. It may be possible to improve code like this by controlling access through e.g. a synchronized wrapper class, or by synchronizing on a field.
Добавлено через 18 минут
Цитата Сообщение от Arsegg Посмотреть сообщение
Гарантия в коде будет только в таком виде
Гарантия такая гарантия...

Кликните здесь для просмотра всего текста

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
public class Meal {
 
    private int id;
    private String name;
    private int price;
 
    public void setId(int id) {
        this.id = id;
    }
 
    public int getId() {
        return id;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getName() {
        return name;
    }
 
    public void setPrice(int price) {
        this.price = price;
    }
 
    public int getPrice() {
        return price;
    }
}
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MealDb {
 
    private static final Map<Integer, Meal> MEAL_MAP = new ConcurrentHashMap<>();
 
    private static final AtomicInteger mealAtomicId = new AtomicInteger();
 
    public void create(Meal meal) {
        synchronized (meal) {
            meal.setId(mealAtomicId.incrementAndGet());
            MealDb.getMealMap().put(meal.getId(), meal);
        }
    }
 
    private static Map<Integer, Meal> getMealMap() {
        return MEAL_MAP;
    }
 
    public int lastId() {
        return mealAtomicId.get();
    }
}


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
public class Bad {
 
    private static final int INVALID_ID = -42;
 
    public static void main(String[] args) {
        int i = 0;
        try {
            for (; i < 100_000; i++) {
                test();
            }
        } catch (Exception e) {
            System.err.printf("ERROR at iteration #%d: %s%n", i, e);
        }
    }
 
    private static void test() throws InterruptedException {
        final var meal = new Meal();
        meal.setName("Breakfast");
        meal.setPrice(12_00);
 
        final var db = new MealDb();
        final var pool = Executors.newFixedThreadPool(2);
        pool.submit(() -> meal.setId(INVALID_ID));
        pool.submit(() -> db.create(meal));
        pool.shutdown();
        if (!pool.awaitTermination(2, TimeUnit.SECONDS)) {
            throw new RuntimeException("failed to terminate thread pool");
        }
 
        if (meal.getId() == INVALID_ID) {
            throw new IllegalStateException("oh no! invalid meal id! Expected: " + db.lastId() + ", got: " + INVALID_ID);
        }
    }
}
Code
1
ERROR at iteration #15: java.lang.IllegalStateException: oh no! invalid meal id! Expected: 16, got: -42
0
3584 / 2184 / 571
Регистрация: 02.09.2015
Сообщений: 5,510
12.06.2021, 15:39
korvin_, и что ты предлагаешь для устранения проблем с многопоточкой? То, что сеттеры зло - это и ежу понятно.
0
Эксперт функциональных языков программированияЭксперт Java
 Аватар для korvin_
4576 / 2775 / 491
Регистрация: 28.04.2012
Сообщений: 8,782
12.06.2021, 15:50
Цитата Сообщение от Arsegg Посмотреть сообщение
и что ты предлагаешь для устранения проблем с многопоточкой?
Я ещё на первой странице написал. Самый простой и надёжный вариант: использовать иммутабельные объекты для доменной модели. Остальное либо сложней, либо не эффективно.
0
3584 / 2184 / 571
Регистрация: 02.09.2015
Сообщений: 5,510
12.06.2021, 15:58
korvin_, ну ок.
Ситуация такая, что на проекте нет возможности переписать мутабельные объекты на их иммутабельные аналоги.
Какие действия? Как обеспечить Thread-Safety?
0
Эксперт функциональных языков программированияЭксперт Java
 Аватар для korvin_
4576 / 2775 / 491
Регистрация: 28.04.2012
Сообщений: 8,782
12.06.2021, 16:57
Цитата Сообщение от Arsegg Посмотреть сообщение
Как обеспечить Thread-Safety?
1) Делаешь Meal потокобезопасным.
2) Добавляешь в Meal метод создания копии.
3) В create первым делом делаешь копию, с ней и работаешь дальше, возвращаешь её как результат create.
4) ?????
5) PROFIT

Об этом я тоже уже писал.
0
12.06.2021, 19:17

Не по теме:

Просвещать этого петросяна явно было лишним.

0
3584 / 2184 / 571
Регистрация: 02.09.2015
Сообщений: 5,510
13.06.2021, 11:03
Цитата Сообщение от korvin_ Посмотреть сообщение
Остальное либо сложней, либо не эффективно.
Есть разница между сложно, потому что не умеешь, и сложно, потому что задача не тривиальная.
Цитата Сообщение от korvin_ Посмотреть сообщение
использовать иммутабельные объекты для доменной модели.
Есть целый пласт задач, где нецелесообразно на каждый чих, создавать копию объекта для изменения одного единственного поля. Например, секвенирование генома: нужно заменить один несчастный ген (или id генома в базе).
Неужели ты на серьезных щах предлагаешь пользователю подождать несколько -ярд секунд вместо того, чтобы просто поставить локи на методы?

Добавлено через 6 минут

Не по теме:

Цитата Сообщение от Tavashi Посмотреть сообщение
Просвещать этого петросяна явно было лишним.
Твоего решения я таки не увидел. Но поговорить ты горазд.

0
Эксперт функциональных языков программированияЭксперт Java
 Аватар для korvin_
4576 / 2775 / 491
Регистрация: 28.04.2012
Сообщений: 8,782
14.06.2021, 00:07
Цитата Сообщение от Arsegg Посмотреть сообщение
Есть разница между сложно, потому что не умеешь, и сложно, потому что задача не тривиальная.
А ещё есть разница между сложно, потому что неуместно.

Цитата Сообщение от Arsegg Посмотреть сообщение
Есть целый пласт задач, где нецелесообразно на каждый чих, создавать копию объекта для изменения одного единственного поля. Например, секвенирование генома: нужно заменить один несчастный ген (или idгенома в базе).
Как хорошо, что к теме это не относится.

Цитата Сообщение от Arsegg Посмотреть сообщение
Неужели ты на серьезных щах предлагаешь пользователю подождать несколько -ярд секунд вместо того, чтобы просто поставить локи на методы?
Неужели ты до сих пор не понял, что твои локи на методах ни от чего не защищают, а в случае ТС'а они ему не нужны вообще? Или ты на серьёзных щас считаешь, что локи -- это капец как дёшево и быстро? Ты на серьёзных щах такой тупой или пьёшь много?
0
3584 / 2184 / 571
Регистрация: 02.09.2015
Сообщений: 5,510
14.06.2021, 01:46
Цитата Сообщение от korvin_ Посмотреть сообщение
а в случае ТС'а они ему не нужны вообще?
Цитата Сообщение от VlGuvin Посмотреть сообщение
Утверждается что операция create является не потокобезопасной поскольку другой какой-то поток может инкрементировать mealAtomicId прежде чем будет put(meal.getId(), meal)
Вопросы:
1. Правильное-ли такое утверждение?
2. Если да то как сделать операцию потокобезопасной?
...
Цитата Сообщение от korvin_ Посмотреть сообщение
Неужели ты до сих пор не понял, что твои локи на методах ни от чего не защищают
Аналогично с твоей иммутабельностью: пользователю ничего не мешает работать напрямую с памятью. К чему это вообще?
Цитата Сообщение от korvin_ Посмотреть сообщение
что локи -- это капец как дёшево и быстро?
А Unpredictable Results - дешево и сердито?
Цитата Сообщение от korvin_ Посмотреть сообщение
Ты на серьёзных щах такой тупой или пьёшь много?
Не позорься: если обосрался, так и скажи.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
14.06.2021, 01:46

Реализация метода
Помогите реализовать метод CreateSession() из библиотеки Avanpost.Idm.Connector.Oracle.dll, который, как написано в документации,...

Реализация метода
Здравствуйте, я совсем немного понимаю в программировании, а все мои знания Java ограничиваются годом обучения в школе Самсунга, поэтому я...

Реализация метода Гаусса на С++
Здравствуйте, пытаюсь найти корни уравнения методом Гаусса, но выводит ерунду, где ошибка? Заранее большое спасибо за помощь! #include...

Реализация метода Чебышева
Здравствуйте. Необходимо решить с помощью маткада любой интеграл методом Чебышева. Не понятно как делать. Толком найти ничего не удалось....

Реализация метода clone
Читаю книгу J.Bloch - Effecitve Java. Не могу понять один абзац. Речь идет о контракте (general contract) метода clone. Вот цитата...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Программное добавление префикса в нумерацию документов
Maks 27.10.2026
Реализация из решения ниже выполнена в самописной конфигурации на БСП (помощь начинающему коллеге). Задача: Программно добавить префикс в нумерацию документов. Решение: В модуле объекта. . .
После закрытия оутлука продолжает висеть процесс в диспетчере задач
Maks 27.10.2026
С недавнего времени в продакшене возникла проблема: при закрытии оутлука в диспетчере задач продолжал висеть процесс outlook. exe. Проблема возникла после установки MS Office 2021 LTSC на машинах, под. . .
Baragoz - DPS/HPS бот для WoW 3.3.5a, многоязычный
AmbA 26.10.2026
Хотите ещё ботов? У меня есть один! А я пока отдохну от него. https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=12062&stc=1&d=1793007952 Инструкция внутри. https:/ / youtu. be/ VpfFZSUDGnQ. . .
Особенности gif сгенерированных в Си
russiannick 21.10.2026
Рассмотрим генерацию gif файлов, которые в Си имеют свои особенности. Gif представляет собой графический формат популярный в интернете. Посмотрим на палитру. Gif файл сгенерированный в си отличается. . .
FPS контроллер с анимированными Y-Bot и 3D-звуком miniaudio (Box3D, Recast, BehaviorTree.CPP, ozz-animation, ImGui, OpenGL и SDL3)
8Observer8 18.10.2026
Содержание блога | English Version Полное мультиплатформенное руководство по стартовому проекту с FPS-контроллером игрока, анимированными роботами Y-Bot с 4-слойным блендингом, 3D-физикой Box3D,. . .
Локальный http сервер
Argus19 17.10.2026
Локальный http сервер На работе, на двух локальных компьютерах круглосуточно работают программы опроса приборов с записью в книги Excel,которые раз в сутки записываются на сервер компании. Т. к. . . .
Копировать Windows на новый диск на UEFI
damix 17.10.2026
https:/ / uriesk. wordpress. com/ 2016/ 11/ 01/ move-window-10-to-ssd-on-a-uefi-dualboot-system-with-basic-linux-tools/ TL DR Вставляем диск, а старый подключаем через переходник, грузимся с лайва. . .
ИИ не может найти нужный язык в списке
Supersumestria 05.10.2026
Я ему даю вот такое изображение и прошу найти и подчеркнуть немецкий язык. Возвращает он вот это: https:/ / i. **********/ vqBWLe2. png Нужную строчку в 3й колонке просто выдумал. . Это. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru