powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / Многопоточная запись в буфер
11 сообщений из 11, страница 1 из 1
Многопоточная запись в буфер
    #37609064
malahov.sa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Помогите, пожалуйста, разобраться со следующей проблемой.
Хочу сделать скидывание сообщений в некий буфер, при достижении порогового значения буфер сохраняется на диск. Код:
Код: 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.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
import java.util.*;

public class ResourceWriter {

    public Map<Integer, Exception> exceptions = new HashMap<Integer, Exception>();
    private Map<String, String> map = new HashMap<String, String>();
    volatile boolean copying=false;
    volatile int count=0;

    public void write(String s){
        if (map.size()<100){
            while (copying){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            map.put(UUID.randomUUID().toString(), s);
            return;
        }
        sendSomewhere();
    }

    private synchronized void sendSomewhere() {
        copying=true;
        if (map.size()<100){
            copying=false;
            return;
        }


        System.out.println("Before flush:"+map.size()+";"+ (++count));
        Map<String, String> map2 = null;
        try {
            map2 = new HashMap<String, String>(map);
        } catch (Exception e) {
            exceptions.put(count, e);
            return;
        }
        map.clear();
        System.out.println("After flush:"+map.size()+";"+count);
        copying=false;
//        отправляем этот map2 куда-нибудь, эмуляция задержки
        try {
            Thread.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

}

public class Worker extends Thread{

    private ResourceWriter rw;

    public Worker(ResourceWriter rw) {
        super();
        this.rw = rw;
    }

    @Override
    public void run() {
        for (int i=0;i<100;i++){
            rw.write(UUID.randomUUID().toString());
        }
    }
}

public class Main {

    public static void main(String[] args) {
        ResourceWriter rw = new ResourceWriter();
        for (int i=0;i<100;i++){
            new Worker(rw).start();
        }
        try {
            Thread.sleep(20000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (Integer key:rw.exceptions.keySet()){
            System.out.println(key+";"+rw.exceptions.get(key).toString());
        }
    }

}



В строке
map2 = new HashMap<String, String>(map);
регулярно возникает ConcurrentModificationException, т.е. эту строку одновременно выполняет несколько потоков.
При этом вывод в консоль имеет следующий вид:

Before flush:104;1
Before flush:111;2
After flush:0;2

Т.е. карта, содержащая 104 строки утеряна. Таким образом получается, что метод
Код: java
1.
private synchronized void sendSomewhere() 


выполняется в нескольких потоках? Естественно, помечать метод write() как synchronized, не хочется
Нормальный вывод имеет вид:
Before flush:125;3
After flush:0;3
Before flush:100;4
After flush:0;4
...
Рейтинг: 0 / 0
Многопоточная запись в буфер
    #37609089
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Взять готовый кэш не вариант? EhCache, например.
...
Рейтинг: 0 / 0
Многопоточная запись в буфер
    #37609096
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ещё для общего развития рекомендую изучить вот этот package
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/package-summary.html
и разобратся с задачей читателей и писателей (ReadWriteLock)
...
Рейтинг: 0 / 0
Многопоточная запись в буфер
    #37609161
Miha_S7
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
malahov.sa,

что касается ошибки, то она возникает при доступе к map. При создании map2 вы указываете базовую карту, доступ к которой не синхронизирован и возможен из write() и sendSomewhere()
...
Рейтинг: 0 / 0
Многопоточная запись в буфер
    #37609190
malahov.sa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
BlazkowiczВзять готовый кэш не вариант? EhCache, например.
Да собственно, он и взят уже) У меня не практический вопрос, а скорее, теоретический. Если честно, смотрел уже в этот пакет, особенно на ConcurrentLinkedQueue. Немного смущает в исходниках наличие misc.unsafe.
...
Рейтинг: 0 / 0
Многопоточная запись в буфер
    #37609199
malahov.sa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Miha_S7,

почему не синхронизирован?
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
    volatile boolean copying=false;
    

    public void write(String s){
        if (map.size()<100){
            while (copying){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            map.put(UUID.randomUUID().toString(), s);
            return;
        }


пока идет копирование add не вызывается.
...
Рейтинг: 0 / 0
Многопоточная запись в буфер
    #37609205
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
[quot malahov.sa]
while (copying) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
[/src]
Это худший вариант синхронизации, который только можно было придумать. Он помимо того что занимает поток так же как и synchronized, так ещё и жрет попусту CPU.
Если это просто неудачная попытка реализовать spinlock, то этого делать не нужно. spinlock уже реализован для synchronized.
...
Рейтинг: 0 / 0
Многопоточная запись в буфер
    #37609214
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
malahov.saЕсли честно, смотрел уже в этот пакет, особенно на ConcurrentLinkedQueue. Немного смущает в исходниках наличие misc.unsafe.
Смущают в каком плане? Слово страшное?
...
Рейтинг: 0 / 0
Многопоточная запись в буфер
    #37609224
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
malahov.saУ меня не практический вопрос, а скорее, теоретический.
Если вопрос теоретический, то я уже дал наиболее полезный совет
1-е разобратся в теоретической задаче читаталей и писателей. Материала даже по-русски валом.
2-е разобратся с вышеуказаным пакетом. Дабы не городить бесполезных Worker-ов и не изобретать Lock заново.
...
Рейтинг: 0 / 0
Многопоточная запись в буфер
    #37609237
Miha_S7
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
malahov.sa,

представим ситуацию.
T1 прошёл по write дошёл до sendSomewhere();

вызывается sendSomewhere: получаем блокировку на this устанавливаем флаг copying

пока мы получали блокировку вылезает другой тред T2, который в строчке while (copying) видит, что флаг не установлен(T1 ещё не установил его, так как занят получением блокировки) и проделывает операции в картой. Дальше всё понятно.

Если вам пришла в голову идея сделать что-нибудь наподобие:
Код: java
1.
2.
3.
4.
private void sendSomewhere() {
    copying=true;
    synchronized {
...


то это плохая идея. Самый простой вариант - использовать ConcurrentHashMap для map и вместо
Код: java
1.
map.clear();


сделать
Код: java
1.
2.
3.
for(String i : map2.keySet()) {
    map.remove(i);
}
...
Рейтинг: 0 / 0
Многопоточная запись в буфер
    #37609262
Miha_S7
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
и, конечно же, убрать флаг copying и всё, что с ним связано
...
Рейтинг: 0 / 0
11 сообщений из 11, страница 1 из 1
Форумы / Java [игнор отключен] [закрыт для гостей] / Многопоточная запись в буфер
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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