Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Threads & vectors


Автор: polakwilno 25.9.2006, 10:55
Добрый день,

Народ, помогите советом, как избавится от такой проблемы:

Код

for(int i=0; i<v.size(); i++)    // v - вектор
    doSomeStuff(v.get(i));


Проблема возникает, когда size() вернет, скажем, 5, а перед вызовом какойто thread удалит один из елементов. Как защитить вектор ТОЛЬКО ОТ УДАЛЕНИЯ - возможность добавления и редактирования должна остатся...

Автор: powerOn 25.9.2006, 11:13
Код

synchronized (v) {
for(int i=0; i<v.size(); i++)    // v - вектор
    doSomeStuff(v.get(i));
}


Автор: polakwilno 25.9.2006, 12:15
Цитата(powerOn @ 25.9.2006,  11:13)
Код

synchronized (v) {
for(int i=0; i<v.size(); i++)    // v - вектор
    doSomeStuff(v.get(i));
}

synchronized() вроде разрешает в тотже момент времени использовать переменную только одному процессу, то есть пока будет выполнятся for цикл я не смогу просто изменить вектор или добавить новый элемент... Или я неправ?

Автор: batigoal 25.9.2006, 12:54
В Java 5 есть пакет concurrent, который позволяет более гибко работать с многопоточностью. В частности, там есть класс ReadWriteLock, который позволяет отдельно блокировать чтение и запись. Но проблемы с апдейтом это не решает.

Добавлено @ 12:56 
На самом деле, я не понял, почему мы синхронизируем цикл for(), а не кусок кода с удалением.

Автор: polakwilno 25.9.2006, 13:05
Цитата(batigoal @ 25.9.2006,  12:54)
Добавлено @ 12:56 
На самом деле, я не понял, почему мы синхронизируем цикл for(), а не кусок кода с удалением.

Так тоже врятли поможет... Получит он размер вектора 5, а потом код с удалением заблокирует вектор, удалит 1 элемент и освободит веткор. А метод get опять-же будет пытатся взять несуществующий элемент... 

Попробую наверно про concurent  почитать, может чего полезного найду...

Автор: LSD 25.9.2006, 13:39
Цитата(polakwilno @  25.9.2006,  14:05 Найти цитируемый пост)
Так тоже врятли поможет... Получит он размер вектора 5, а потом код с удалением заблокирует вектор, удалит 1 элемент и освободит веткор. А метод get опять-же будет пытатся взять несуществующий элемент... 

Это поможет. Все методы меняющие java.util.Vector просто объявлены synchronized, поэтому захватив блокировку на этот Vector мы предотвратим все вызовы подобных методов. В том числе и insertElementAt() и set() и даже indexOf().

В принципе есть java.util.concurrent.CopyOnWriteArrayList - когда список менятся, создается новая копия массива используемого для хранения элементов. Таким образом итератор, всегда работает со старым вариантом списка, но это делает вставленные и измененные элементы невидимыми для итератора.

Автор: polakwilno 25.9.2006, 14:25
Цитата(LSD @ 25.9.2006,  13:39)
Это поможет.

Возможно сама идея правильная, но мне кажется появится много багов изза того что ктото чегото не сможет записать пока вектор будет заблокирован... Но конечно надеюсь, что все будет работать нормально smile

Потестирую сервак 1-2 дня потом напишу что получилось ;)

Автор: LSD 25.9.2006, 14:28
Цитата(polakwilno @  25.9.2006,  15:25 Найти цитируемый пост)
мне кажется появится много багов изза того что ктото чегото не сможет записать пока вектор будет заблокирован...

Ну вообщем, да, тут будет почти полная блокировка.

Если тебе надо блокировать тольку удаление, то придется писать свою коллекцию.

Автор: powerOn 25.9.2006, 14:34
Цитата(batigoal @  25.9.2006,  13:54 Найти цитируемый пост)
На самом деле, я не понял, почему мы синхронизируем цикл for(), а не кусок кода с удалением. 


мы синхронизируем не сколько цикл for, сколько участок кода работающий с объектом вектора. Вот и весь смысл.

Автор: polakwilno 25.9.2006, 15:22
Цитата(LSD @ 25.9.2006,  14:28)
Если тебе надо блокировать тольку удаление, то придется писать свою коллекцию.

LSD, удаление как таковое я заблокировал... Сделал специяльные методы get() и setFree(), которые увеличивают/уменьшают счетчик процесов, которые в данный момент используют вектор. А thread который удаляет ненужные элементы вектора, смотрит равен-ли счетчик 0, если да то удаляет, иначе - пропускает. 

Пробовал сделать похожее с функцией size() - увеличить счетчик а потом уменьшить, но тут много нюансов - делаешь чтоб работало в 1 месте - не работает в другом... В принципе, если synchronized() не поможет придется както делать счетчик на size()... Придется очень много переделать, но зато реально добится нужного результата. Просто думал попробую решить стандартными средствами, без всяких наворотов... smile


Хе хе, прикольная ошибка
Цитата

ERROR: Cannot find database vingrad_pforum Возникла SQL ошибка при обращении к БД форума.
PS: Э...э бывает smile

Автор: LSD 25.9.2006, 16:09
Думаю тут лучше использовать ReentrantReadWriteLock.
Создаешь объект ReentrantReadWriteLock, затем читающий поток делает lock.readLock().lock() (если сейчас коллекция заблокированна на запись, то он просто встанет), работаешь с коллекцией, затем после того как читающий поток отработал делаешь lock.readLock().unlock(). Когда пишущему потоку надо будет изменять коллекцию, делаешь lock.writeLock().lock() (он тоже встанет, если сейчас кто-то читает из коллекции), когда пишущий поток закончит менять коллекцию: lock.writeLock().unlock().
Пишущий поток получает эксклюзивную блокировку на объект, читающие потоки не эксклюзивную. Плюс можно устанавливать таймауты на ожидание блокировки.

Автор: polakwilno 26.9.2006, 22:42
Ну вот, уже 2 дня все работает нормально (раньше регулярно раз в день зависалsmile). Думаю, проблема решена...

Всем спасибо, в который раз выручаете ;)

Ай да, помог обычный Synchronized(vector). Поставил его на цикл, который ищет вектора на удаление...

Автор: COVD 26.9.2006, 23:08
Ну вот, люди в Sun стараются, придумывают всякие lock.readLock().unlock().lock().unlock().., а вы обычный synchronize() применяете  smile 

Автор: polakwilno 29.9.2006, 00:08
Цитата(COVD @ 26.9.2006,  23:08)
Ну вот, люди в Sun стараются, придумывают всякие lock.readLock().unlock().lock().unlock().., а вы обычный synchronize() применяете  smile

 smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)