|
ConcurrentMap и многопоточность
|
|||
---|---|---|---|
#18+
Всем добрый вечер! Есть небольшой утильный класс, который собирает количество пришедших сообщений, а потом раз в определенный промежуток времени скидывает значения в базу данных. Класс используют сразу несколько потоков Написать я его написал, но, чувствую, что излишне нахимичил и слегка поплыл в многопоточности Код: 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. 35. 36.
Есть несколько вопросов: 1. Насколько я понимаю, все потоки видят текущее состояние ConcurrentMap и volitile у поля ставить не надо? 2. Насколько я почитал, value у ConcurrentMap volitile, и не будет ли здесь излишним использование атомика для инкремента? 3. Возможно ли обойтись без блокировок? Класс сам по себе чисто утильный, второстепенный и не хотелось бы, чтобы он сильно влиял на работу основной логики. А сейчас он влияет, так как запись в бд может подтормаживать ... |
|||
:
Нравится:
Не нравится:
|
|||
13.01.2020, 22:44 |
|
ConcurrentMap и многопоточность
|
|||
---|---|---|---|
#18+
Timein Всем добрый вечер! Есть небольшой утильный класс, который собирает количество пришедших сообщений, а потом раз в определенный промежуток времени скидывает значения в базу данных. Класс используют сразу несколько потоков Написать я его написал, но, чувствую, что излишне нахимичил и слегка поплыл в многопоточности Код: 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. 35. 36.
Есть несколько вопросов: 1. Насколько я понимаю, все потоки видят текущее состояние ConcurrentMap и volitile у поля ставить не надо? 2. Насколько я почитал, value у ConcurrentMap volitile, и не будет ли здесь излишним использование атомика для инкремента? 3. Возможно ли обойтись без блокировок? Класс сам по себе чисто утильный, второстепенный и не хотелось бы, чтобы он сильно влиял на работу основной логики. А сейчас он влияет, так как запись в бд может подтормаживать Добрый вечер!Проще было бы производить запись из коллекции в БД отдельными порциями и асинхронно. Если у вас накопится достаточно большой объём данных то скинуть его в бд будет проблематично с точки зрения времени удержания блокировки для остальных операций, возникнет провал ... |
|||
:
Нравится:
Не нравится:
|
|||
13.01.2020, 23:38 |
|
ConcurrentMap и многопоточность
|
|||
---|---|---|---|
#18+
Timein, 3. Пишем в бд отдельным фоновым потоком. Ничего тормозить не будет. Блокировать ничего не надо. А основная логика в основном потоке. ... |
|||
:
Нравится:
Не нравится:
|
|||
13.01.2020, 23:40 |
|
ConcurrentMap и многопоточность
|
|||
---|---|---|---|
#18+
Timein, 1. Делать AtomicInteger внутри мапы counts не нужно, это перебор. 2. Использовать reentrantlock(synchronized) в методе addCount также не нужно, но вместо put я бы посоветовал использовать putIfAbsent (computeIfAbsent). Посмотрите по докам как их использовать. ... |
|||
:
Нравится:
Не нравится:
|
|||
13.01.2020, 23:57 |
|
ConcurrentMap и многопоточность
|
|||
---|---|---|---|
#18+
L.Otujktd Если у вас накопится достаточно большой объём данных то скинуть его в бд будет проблематично с точки зрения времени удержания блокировки для остальных операций, возникнет провал Нет, с объемом данных проблем не будет - заведомо известно, что он небольшой (не более 30 ключей) L.Otujktd Проще было бы производить запись из коллекции в БД отдельными порциями и асинхронно. PetroNotC Sharp Ничего тормозить не будет. Блокировать ничего не надо. А основная логика в основном потоке. Добавил executor. Или я неправильно понял идею? Код: 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. 35. 36. 37. 38.
Tropic Timein, 1. Делать AtomicInteger внутри мапы counts не нужно, это перебор. 2. Использовать reentrantlock(synchronized) в методе addCount также не нужно, но вместо put я бы посоветовал использовать putIfAbsent (computeIfAbsent). Посмотрите по докам как их использовать. Насколько я понимаю, putIfAbsent заменяет put, если значение отсутствует (ну или вычисляет его), но у меня есть вторая ветка - когда значение есть. И выигрыш получается не слишком большим ... |
|||
:
Нравится:
Не нравится:
|
|||
14.01.2020, 00:18 |
|
ConcurrentMap и многопоточность
|
|||
---|---|---|---|
#18+
Timein, Я имел ввиду, что каждый поток берет из пула себе коннект и пишет в бд. Этот класс не нужен вообще. Зачем пересоздавать коллекцию каждый раз? Блокировка уже есть внутри потокозащищенных классов. ... |
|||
:
Нравится:
Не нравится:
|
|||
14.01.2020, 07:38 |
|
ConcurrentMap и многопоточность
|
|||
---|---|---|---|
#18+
я так понимаю, lock при текущей реализации должен защищать от вставки в мап при записи в базу. 1. поэтому в методе addCount можно было бы использовать read lock, чтоб вставка в мап была многопоточной, а в методе writeToDB использовать write lock 2. если заменить ConcurrentMap<String, AtomicInteger> counts на неблокирующую конкурентную очередь, то можно было бы одновременно писать в хвост очереди и читать из головы очереди и записывать кусками в базу, не используя ни один lock ... |
|||
:
Нравится:
Не нравится:
|
|||
14.01.2020, 11:38 |
|
ConcurrentMap и многопоточность
|
|||
---|---|---|---|
#18+
сладкий бубалех, Да. Чем меньше блокировок тем лучше. Непонятно зачем тормозить вставку в мап при записи в бд? ... |
|||
:
Нравится:
Не нравится:
|
|||
14.01.2020, 11:52 |
|
ConcurrentMap и многопоточность
|
|||
---|---|---|---|
#18+
PetroNotC Sharp сладкий бубалех, Непонятно зачем тормозить вставку в мап при записи в бд? это так же как с получением количества элементов у конкурентных коллекций, они неточные. имхо, чтобы пройтись по всем элементам коллекции и записать их в базу и не получить конкурентную вставку там где мы уже прошли, нужна блокировка на вставку. после записи в базу мы должны очистить коллекцию, и наша неучтенная конкурентная вставка при записи в бд пропадет, если не было блокировки на вставку ... |
|||
:
Нравится:
Не нравится:
|
|||
14.01.2020, 12:09 |
|
ConcurrentMap и многопоточность
|
|||
---|---|---|---|
#18+
сладкий бубалех, Для такой ерунды есть готовые коллекции вроде. Чтобы не было райзе в цикле for ... |
|||
:
Нравится:
Не нравится:
|
|||
14.01.2020, 12:23 |
|
ConcurrentMap и многопоточность
|
|||
---|---|---|---|
#18+
Timein, эффективность решения данной задачи будет зависеть от того что ты вообще хочешь получить в результате? 1) Абсолютно точное синхронное представление счетчиков ConcurrentMap<String, AtomicInteger> counts в базе. Будет один алгоритм. Дорого в ресурсах. Не сложно. Нет никаких блокировок. Полагаемся на БД. И на ее скорость. 2) Отложенное но консистентное между счетчиками состояние. Приводит в твоем алгоритме к ожиданию блока. Работает но непонятно зачем нам ждать. 3) Можно сделать буферизованное фоновое сохранение счетчиков через буферок типа BlockingQueue или любую другую очередь и получать мягкое и почти не блокирующее не-консистентное состояние. В конце этого метода (3) надо перед стопом приложения сделать некий flush() чтобы полностью дождаться сохранения очереди в БД. ... |
|||
:
Нравится:
Не нравится:
|
|||
14.01.2020, 18:02 |
|
ConcurrentMap и многопоточность
|
|||
---|---|---|---|
#18+
Не обязательно ставить блокировку на все время записи в БД (медленно) 1. блокировать 2. копировать counts в другую (можно аналогичную) временную структуру (относительно быстро) 3. снимать блокировку 4. В БД записывать уже копию с шага 2 (медленно, но ничего не блокируем) ... |
|||
:
Нравится:
Не нравится:
|
|||
14.01.2020, 18:08 |
|
|
start [/forum/topic.php?fid=59&msg=39913420&tid=2120952]: |
0ms |
get settings: |
26ms |
get forum list: |
16ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
51ms |
get topic data: |
11ms |
get forum data: |
3ms |
get page messages: |
271ms |
get tp. blocked users: |
2ms |
others: | 308ms |
total: | 696ms |
0 / 0 |