powered by simpleCommunicator - 2.0.30     © 2024 Programmizd 02
Map
Форумы / Java [игнор отключен] [закрыт для гостей] / ConcurrentMap и многопоточность
12 сообщений из 12, страница 1 из 1
ConcurrentMap и многопоточность
    #39913420
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.
@Component
public class CountsUtil {

    private ConcurrentMap<String, AtomicInteger> counts;
    private ReentrantLock reentrantLock = new ReentrantLock();
    @Autowired
     private DBWriter dbWriter;

    public CountsUtil() {
        this.counts = new ConcurrentHashMap<>();
    }

    public void addCount(String name) {
        try {
            reentrantLock.lock();
            if (counts.containsKey(name)) {
                counts.get(name).getAndIncrement();
            } else {
                counts.put(name, new AtomicInteger(1));
            }
        } finally {
            reentrantLock.unlock();
        }
    }

    public void writeToDB() {
        try {
            reentrantLock.lock();
            dbWriter.write(counts);
            counts = new ConcurrentHashMap<>();
        } finally {
            reentrantLock.unlock();
        }
    }
//остальная логика
}


Есть несколько вопросов:
1. Насколько я понимаю, все потоки видят текущее состояние ConcurrentMap и volitile у поля ставить не надо?
2. Насколько я почитал, value у ConcurrentMap volitile, и не будет ли здесь излишним использование атомика для инкремента?
3. Возможно ли обойтись без блокировок? Класс сам по себе чисто утильный, второстепенный и не хотелось бы, чтобы он сильно влиял на работу основной логики. А сейчас он влияет, так как запись в бд может подтормаживать
...
Рейтинг: 0 / 0
ConcurrentMap и многопоточность
    #39913429
L.Otujktd
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
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.
@Component
public class CountsUtil {

    private ConcurrentMap<String, AtomicInteger> counts;
    private ReentrantLock reentrantLock = new ReentrantLock();
    @Autowired
     private DBWriter dbWriter;

    public CountsUtil() {
        this.counts = new ConcurrentHashMap<>();
    }

    public void addCount(String name) {
        try {
            reentrantLock.lock();
            if (counts.containsKey(name)) {
                counts.get(name).getAndIncrement();
            } else {
                counts.put(name, new AtomicInteger(1));
            }
        } finally {
            reentrantLock.unlock();
        }
    }

    public void writeToDB() {
        try {
            reentrantLock.lock();
            dbWriter.write(counts);
            counts = new ConcurrentHashMap<>();
        } finally {
            reentrantLock.unlock();
        }
    }
//остальная логика
}


Есть несколько вопросов:
1. Насколько я понимаю, все потоки видят текущее состояние ConcurrentMap и volitile у поля ставить не надо?
2. Насколько я почитал, value у ConcurrentMap volitile, и не будет ли здесь излишним использование атомика для инкремента?
3. Возможно ли обойтись без блокировок? Класс сам по себе чисто утильный, второстепенный и не хотелось бы, чтобы он сильно влиял на работу основной логики. А сейчас он влияет, так как запись в бд может подтормаживать

Добрый вечер!Проще было бы производить запись из коллекции в БД отдельными порциями и асинхронно. Если у вас накопится достаточно большой объём данных то скинуть его в бд будет проблематично с точки зрения времени удержания блокировки для остальных операций, возникнет провал
...
Рейтинг: 0 / 0
ConcurrentMap и многопоточность
    #39913430
PetroNotC Sharp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Timein,
3. Пишем в бд отдельным фоновым потоком.
Ничего тормозить не будет. Блокировать ничего не надо. А основная логика в основном потоке.
...
Рейтинг: 0 / 0
ConcurrentMap и многопоточность
    #39913434
Tropic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Timein,

1. Делать AtomicInteger внутри мапы counts не нужно, это перебор.

2. Использовать reentrantlock(synchronized) в методе addCount также не нужно, но вместо put я бы посоветовал использовать putIfAbsent (computeIfAbsent). Посмотрите по докам как их использовать.
...
Рейтинг: 0 / 0
ConcurrentMap и многопоточность
    #39913435
Timein
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
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.
public class CountsUtil {

    private ConcurrentMap<String, AtomicInteger> counts;
    private ReentrantLock reentrantLock = new ReentrantLock();
    private ScheduledExecutorService executor;
    @Autowired
    private DBWriter dbWriter;

    public CountsUtil() {
        this.counts = new ConcurrentHashMap<>();
        dbWriter = new DBWriter();
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);
        pool.schedule(this::writeToDB, 60, TimeUnit.SECONDS);
    }

    public void addCount(String name) {
        try {
            reentrantLock.lock();
            if (counts.containsKey(name)) {
                counts.get(name).getAndIncrement();
            } else {
                counts.put(name, new AtomicInteger(1));
            }
        } finally {
            reentrantLock.unlock();
        }
    }

    public void writeToDB() {
        try {
            reentrantLock.lock();
            dbWriter.write(counts);
            counts = new ConcurrentHashMap<>();
        } finally {
            reentrantLock.unlock();
        }
    }
}





Tropic
Timein,

1. Делать AtomicInteger внутри мапы counts не нужно, это перебор.

2. Использовать reentrantlock(synchronized) в методе addCount также не нужно, но вместо put я бы посоветовал использовать putIfAbsent (computeIfAbsent). Посмотрите по докам как их использовать.

Насколько я понимаю, putIfAbsent заменяет put, если значение отсутствует (ну или вычисляет его), но у меня есть вторая ветка - когда значение есть. И выигрыш получается не слишком большим
...
Рейтинг: 0 / 0
ConcurrentMap и многопоточность
    #39913459
PetroNotC Sharp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Timein,
Я имел ввиду, что каждый поток берет из пула себе коннект и пишет в бд.
Этот класс не нужен вообще.
Зачем пересоздавать коллекцию каждый раз?
Блокировка уже есть внутри потокозащищенных классов.
...
Рейтинг: 0 / 0
ConcurrentMap и многопоточность
    #39913555
я так понимаю, lock при текущей реализации должен защищать от вставки в мап при записи в базу.
1. поэтому в методе addCount можно было бы использовать read lock, чтоб вставка в мап была многопоточной, а в методе writeToDB использовать write lock

2. если заменить ConcurrentMap<String, AtomicInteger> counts на неблокирующую конкурентную очередь, то можно было бы одновременно писать в хвост очереди и читать из головы очереди и записывать кусками в базу, не используя ни один lock
...
Рейтинг: 0 / 0
ConcurrentMap и многопоточность
    #39913565
PetroNotC Sharp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
сладкий бубалех,
Да.
Чем меньше блокировок тем лучше.
Непонятно зачем тормозить вставку в мап при записи в бд?
...
Рейтинг: 0 / 0
ConcurrentMap и многопоточность
    #39913579
PetroNotC Sharp
сладкий бубалех,
Непонятно зачем тормозить вставку в мап при записи в бд?


это так же как с получением количества элементов у конкурентных коллекций, они неточные.

имхо, чтобы пройтись по всем элементам коллекции и записать их в базу и не получить конкурентную вставку там где мы уже прошли, нужна блокировка на вставку. после записи в базу мы должны очистить коллекцию, и наша неучтенная конкурентная вставка при записи в бд пропадет, если не было блокировки на вставку
...
Рейтинг: 0 / 0
ConcurrentMap и многопоточность
    #39913590
PetroNotC Sharp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
сладкий бубалех,
Для такой ерунды есть готовые коллекции вроде.
Чтобы не было райзе в цикле for
...
Рейтинг: 0 / 0
ConcurrentMap и многопоточность
    #39913873
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Timein, эффективность решения данной задачи будет зависеть от того что ты вообще хочешь получить в результате?

1) Абсолютно точное синхронное представление счетчиков ConcurrentMap<String, AtomicInteger> counts в базе.
Будет один алгоритм. Дорого в ресурсах. Не сложно. Нет никаких блокировок. Полагаемся на БД. И на ее скорость.

2) Отложенное но консистентное между счетчиками состояние. Приводит в твоем алгоритме к ожиданию блока.
Работает но непонятно зачем нам ждать.

3) Можно сделать буферизованное фоновое сохранение счетчиков через буферок типа BlockingQueue или
любую другую очередь и получать мягкое и почти не блокирующее не-консистентное состояние.

В конце этого метода (3) надо перед стопом приложения сделать некий flush() чтобы полностью
дождаться сохранения очереди в БД.
...
Рейтинг: 0 / 0
ConcurrentMap и многопоточность
    #39913880
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Не обязательно ставить блокировку на все время записи в БД (медленно)
1. блокировать
2. копировать counts в другую (можно аналогичную) временную структуру (относительно быстро)
3. снимать блокировку
4. В БД записывать уже копию с шага 2 (медленно, но ничего не блокируем)
...
Рейтинг: 0 / 0
12 сообщений из 12, страница 1 из 1
Форумы / Java [игнор отключен] [закрыт для гостей] / ConcurrentMap и многопоточность
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]