powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / Синхронизация по String
36 сообщений из 36, показаны все 2 страниц
Синхронизация по String
    #37735089
shainsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Кто подскажет шаблон для синхронизации кода не по экземпляру объекта, а по строке?

То есть чтобы одновременные вызовы someMethod("a") и someMethod("b") выполнялись параллельно, а вызовы someMethod("a") и someMethod("a") - по очереди.

Я придумал такой код, но есть подозрения в том, что он неоптимален:

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
 

    static ConcurrentMap<String, String> workWith = new ConcurrentHashMap<String, String>();
         ...
        
    void someMethod(String s) {

        String current = workWith.putIfAbsent(s, s);
        if (current == null)
            current = s;
        synchronized (current) {

         // синхронизированный код ...

            workWith.remove(s);
        }
    }
...
Рейтинг: 0 / 0
Синхронизация по String
    #37735122
забыл ник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А чего вы хотите добиться? Я имею ввиду, что возможно вы идете окружным путем, а решение проще и элегантней. Что касается того кода что вы привели, выполнить какой-то код, основываясь на параметре, то да, можно завести коллекцию, не обязательно ConcurrentHashMap, в цикле делать CAS, ожидая пока ячейка освободиться, и когда освободиться выполнить свой код, Только опять же иногда CAS намного хуже чем обычный Lock, если contention большой. Можете описать задачу конкретней?
...
Рейтинг: 0 / 0
Синхронизация по String
    #37735123
забыл ник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я так полагаю что это какое-то подобие кэша, который поддерживает работу с несколькими потоками? Тогда вам определенно надо скачать Java Concurrency in practice, там целая глава посвящена кэшам, и есть там хороший пример с Future и Computable
...
Рейтинг: 0 / 0
Синхронизация по String
    #37735188
shainsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
забыл ник,

Это не подобие хэша. Я пишу обработчик вызовов удаленного метода.
У меня есть некая сущность, скажем, клиентский счет. Он идентифицируется строковым UUID'ом. Таких сущностей на сервере может быть несколько тысяч.
Мне надо делать синхронизацию на основе UUID'а.
Чтобы два клиента одновременно не редактировали одновременно эту сущность.
...
Рейтинг: 0 / 0
Синхронизация по String
    #37735218
Йуный джавистЪ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Во-первых, я не очень понимаю, зачем нужна проверка на null.
Во-вторых, что из себя представляет эта сущность? Если это объект внутри JVM, то синхронизируйтесь прям на нем. Если это строчка в базе данных, то захватывайте лок на этой строчке в БД (это происходит автоматически при update или delete).
...
Рейтинг: 0 / 0
Синхронизация по String
    #37735224
забыл ник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторВо-вторых, что из себя представляет эта сущность? Если это объект внутри JVM, то синхронизируйтесь прям на нем. Если это строчка в базе данных, то захватывайте лок на этой строчке в БД (это происходит автоматически при update или delete).

Я тоже так думаю, может топикстартер чего-то недоговаривает?
...
Рейтинг: 0 / 0
Синхронизация по String
    #37735225
shainsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Йуный джавистЪВо-первых, я не очень понимаю, зачем нужна проверка на null.
Почитайте джавадок метода ConcurrentMap.putIfAbsent()

Йуный джавистЪВо-вторых, что из себя представляет эта сущность? Если это объект внутри JVM, то синхронизируйтесь прям на нем.
Спасибо, кэп! :)

Йуный джавистЪЕсли это строчка в базе данных, то захватывайте лок на этой строчке в БД (это происходит автоматически при update или delete).
Это сущность в нереляционном дата-бэкенде.
...
Рейтинг: 0 / 0
Синхронизация по String
    #37735241
shainsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
забыл никавторВо-вторых, что из себя представляет эта сущность? Если это объект внутри JVM, то синхронизируйтесь прям на нем. Если это строчка в базе данных, то захватывайте лок на этой строчке в БД (это происходит автоматически при update или delete).

Я тоже так думаю, может топикстартер чего-то недоговаривает?

Это сущность в самописном нереляционном дата-бэкенде. У меня нет уверенности в корректной поддержке конкурентной модификации сущностей внутри этого бэкенда.
...
Рейтинг: 0 / 0
Синхронизация по String
    #37735242
Йуный джавистЪ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Почитайте джавадок метода ConcurrentMap.putIfAbsent()
Теперь понял.
Это сущность в нереляционном дата-бэкенде.

Можно поинтересоваться, в каком? Даже в файловой системе есть локи.
...
Рейтинг: 0 / 0
Синхронизация по String
    #37735253
shainsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Это сущность в нереляционном дата-бэкенде.

Можно поинтересоваться, в каком? Даже в файловой системе есть локи.

Кэширующее реплицируемое хранилище игровых объектов. По сути легаси-система, написана на С++. Используется в многопользовательской игре. Количество типов объектов ограничено и заранее описано. Не знаю, что ещё рассказать Вам о нем.
...
Рейтинг: 0 / 0
Синхронизация по String
    #37735265
Фотография schwa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
shainsky,

Кладите вместо строки либо просто новый созданный объект, либо какую-нибудь из реализаций java.util.concurrent.locks.Lock
...
Рейтинг: 0 / 0
Синхронизация по String
    #37735274
shainsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
schwashainsky,

Кладите вместо строки либо просто новый созданный объект, либо какую-нибудь из реализаций java.util.concurrent.locks.Lock

Вместо current = s написать current = new Object() ?
А в чем здесь оптимизация? В моем случае кладется уже существующий объект, а в Вашем - новый, который надо создавать и хранить.
Или я неправильно понял?
...
Рейтинг: 0 / 0
Синхронизация по String
    #37735295
Фотография schwa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вы не то оптимизируете - вам нужно оптимизировать время пребывания в блоке synchronized и количество тех, кто борется за это монитор.
...
Рейтинг: 0 / 0
Синхронизация по String
    #37735298
Фотография schwa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
За этоТ монитор, который создается, или достается из мапа, а вы боритесь с GC вместо этого.
...
Рейтинг: 0 / 0
Синхронизация по String
    #37735480
Фотография grasoff.net
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
intern() но это не очень здорово, поэтому проще создать
Код: java
1.
2.
3.
4.
5.
6.
class StringMutex {
  private String value;
  Mutex(String value) {this.value = value;}
  hashcode() {...}
  equals() {...}
}


и синхронизироваться по нему
...
Рейтинг: 0 / 0
Синхронизация по String
    #37735488
OOsalivan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
shainsky,

Еще вариант
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
private final ConcurrentMap<String, Boolean> map = new ConcurrentHashMap<String, Boolean>();
	private final Object lock = new Object();
	
	void someMethod(String s) throws InterruptedException {	
		while (map.put(s, true) == true) {
			synchronized (lock) {
				lock.wait();
			}		
		}
		//синхронизированный код	
		map.put(s, false);
		lock.notifyAll();
	}
...
Рейтинг: 0 / 0
Синхронизация по String
    #37735545
забыл ник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
OOsalivanshainsky,

Еще вариант
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
private final ConcurrentMap<String, Boolean> map = new ConcurrentHashMap<String, Boolean>();
	private final Object lock = new Object();
	
	void someMethod(String s) throws InterruptedException {	
		while (map.put(s, true) == true) {
			synchronized (lock) {
				lock.wait();
			}		
		}
		//синхронизированный код	
		map.put(s, false);
		lock.notifyAll();
	}


Зачем эта мутотень если уже 5 лет есть Lock?
...
Рейтинг: 0 / 0
Синхронизация по String
    #37735769
OOsalivan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
забыл никЗачем эта мутотень если уже 5 лет есть Lock?

Lock есть, и как вы его собираетесь к этой задаче применить, где ваш код?
Или это самоутверждение?
...
Рейтинг: 0 / 0
Синхронизация по String
    #37735781
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
schwaВы не то оптимизируете - вам нужно оптимизировать время пребывания в блоке synchronized и количество тех, кто борется за это монитор.
+1
...
Рейтинг: 0 / 0
Синхронизация по String
    #37735783
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
OOsalivanshainsky,

Еще вариант
Код: java
1.
2.
3.
4.
5.
		while (map.put(s, true) == true) {
			synchronized (lock) {
				lock.wait();
			}		
		}


Как на счет spurious wakeup?
...
Рейтинг: 0 / 0
Синхронизация по String
    #37735791
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
OOsalivanLock есть, и как вы его собираетесь к этой задаче применить, где ваш код?
Или это самоутверждение?
Всё тоже самое, только вместо Object - Lock и synchronized не нужен.
Lock рекомедуют к использованию вместо wait/notify. Но мне любопытно на счет производительности. Lock устроен горзда сложнее с кучей вызовов методов.
...
Рейтинг: 0 / 0
Синхронизация по String
    #37736035
OOsalivan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczOOsalivanshainsky,

Еще вариант
Код: java
1.
2.
3.
4.
5.
		while (map.put(s, true) == true) {
			synchronized (lock) {
				lock.wait();
			}		
		}


Как на счет spurious wakeup?

А где вы видите проблему с spurious wakeup?

while (map.put(s, true) == true) - как раз для этого и написано
...
Рейтинг: 0 / 0
Синхронизация по String
    #37736077
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
OOsalivanА где вы видите проблему с spurious wakeup?
while (map.put(s, true) == true) - как раз для этого и написано
Ааа, там предыдущее значение выталкивается. Я подумал что флаг. А NPE не будет ли при анбоксинге null? В любом случае при первом заходе там всегда не true. Рантайм в цикл вообще не попадёт.
...
Рейтинг: 0 / 0
Синхронизация по String
    #37736083
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczАаа, там предыдущее значение выталкивается. Я подумал что флаг. А NPE не будет ли при анбоксинге null? В любом случае при первом заходе там всегда не true. Рантайм в цикл вообще не попадёт.
Ой, блин что-то я гоню. Это же только для того случая если строка есть.
А ещё вопрос, все ведь строки на одном локе висят. Тогда если две разных строки в 2х потоках уже существуею, они ещё и с друг другом будут бодаться за lock?
...
Рейтинг: 0 / 0
Синхронизация по String
    #37736090
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
И ещё вопрос к коду. Как отработает re-entrancy, если метод вызовется для той же строки, но в том же потоке?
...
Рейтинг: 0 / 0
Синхронизация по String
    #37736098
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А ещё, расскажи, если не трудно, для чего true/false. Не проще ли через Set и проверку на null?
...
Рейтинг: 0 / 0
Синхронизация по String
    #37736219
OOsalivan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczBlazkowiczАаа, там предыдущее значение выталкивается. Я подумал что флаг. А NPE не будет ли при анбоксинге null? В любом случае при первом заходе там всегда не true. Рантайм в цикл вообще не попадёт.
Ой, блин что-то я гоню. Это же только для того случая если строка есть.
А ещё вопрос, все ведь строки на одном локе висят. Тогда если две разных строки в 2х потоках уже существуею, они ещё и с друг другом будут бодаться за lock?

Когда поток переходит в состояние wait он освобождает монитор объекта.
Поэтому все строки которые соответствуют
map.put(s, true) == true - т.е предыдущее значение для данного ключа(строки) == true - будут переходить в состояние wait.
...
Рейтинг: 0 / 0
Синхронизация по String
    #37736247
OOsalivan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczИ ещё вопрос к коду. Как отработает re-entrancy, если метод вызовется для той же строки, но в том же потоке?

Когда поток вызывает lock.notifyAll(); он переводит все потоки(которые висят на данном локе) в активное состояние. Если у нас есть стек потоков с одним ключом (s) которые на момент lock.notifyAll() висели на нашем локе - то первый из них выигрывает ресурс map.put(s, true) == false и работает с критической областью, а остальные по условию map.put(s, true) == true переходят в состояние wait.
...
Рейтинг: 0 / 0
Синхронизация по String
    #37736260
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
notifyAll() тоже ведь завернуть нужно в synchronized
...
Рейтинг: 0 / 0
Синхронизация по String
    #37736269
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
OOsalivanКогда поток вызывает lock.notifyAll(); он переводит все потоки(которые висят на данном локе) в активное состояние. Если у нас есть стек потоков с одним ключом (s) которые на момент lock.notifyAll() висели на нашем локе - то первый из них выигрывает ресурс map.put(s, true) == false и работает с критической областью, а остальные по условию map.put(s, true) == true переходят в состояние wait.
Нее, re-entrancy, это про один поток. Если вдруг поток вызовет метод, положит строку и потом в какой-то момент снова вызовет этот же метод. Он же залочится до тех пор пока кто-то по другой строке его не разбудит.
...
Рейтинг: 0 / 0
Синхронизация по String
    #37736344
OOsalivan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczА ещё, расскажи, если не трудно, для чего true/false. Не проще ли через Set и проверку на null?
Можно и через Set - только какую имплиминтацию брать?

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
   private final Object lock = new Object();
    private final Set<String> set = new //Concurrent implementation;

    void someMethod(String s) throws InterruptedException {
        synchronized (lock) {
            while (set.add(s) != true) {
                lock.wait();
            }
        }
        // синхронизированный код
        set.remove(s);
        synchronized (lock) {
            lock.notifyAll();
        }
    }
...
Рейтинг: 0 / 0
Синхронизация по String
    #37736357
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
OOsalivanМожно и через Set - только какую имплиминтацию брать?

Collections.newSetFromMap()
...
Рейтинг: 0 / 0
Синхронизация по String
    #37736479
забыл ник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczLock рекомедуют к использованию вместо wait/notify. Но мне любопытно на счет производительности. Lock устроен горзда сложнее с кучей вызовов методов.

Насчет производительности - многое зависит от имплементации JVM, но если брать HotSpot, то рекомендуют использовать synchronized в случае если с кодом работает в основном один поток, причем если синхронизация происходит все время по одному объекту(так как возможно применить так называемый biased locking), в данном случае это не наблюдается. Вариант когда с кодом работает один поток, но синхронизация по разным объектам и количество "столкновений на мониторе" невысоко, то оба подхода дают примерно одинаковый результат, так как оба работают на CASе, а вот выигрывать Lock начинает при большом столкновении, так как synch сразу раздувается до OS-level монитора, а Lock имплементирован так, что может адаптивно подстраиваится, и перейти на OS-level и обратно при определенных условиях. Все это более подробно описывается тут - http://www.javaspecialist.ru/2011/11/synchronized-vs-reentrantlock.html#more

BlazkowiczА ещё вопрос, все ведь строки на одном локе висят. Тогда если две разных строки в 2х потоках уже существуею, они ещё и с друг другом будут бодаться за lock?
И ещё вопрос к коду. Как отработает re-entrancy, если метод вызовется для той же строки, но в том же потоке?

Вот именно поэтому я и говорю, что надо использовать ReentrantLock, причем он должен быть не глобальным, а содержаться в Map

Код: java
1.
private final ConcurrentMap<String, ReentrantLock> map = new ConcurrentHashMap<String, ReentrantLock>();



и лочить надо именно не глобальный лок, а тот что доступен по ключу-строке, тогда столкновений на разных строках на одном мониторе не будет, что значительно увеличит производительность, как вы и заметили.
...
Рейтинг: 0 / 0
Синхронизация по String
    #37736498
OOsalivan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczНее, re-entrancy, это про один поток. Если вдруг поток вызовет метод, положит строку и потом в какой-то момент снова вызовет этот же метод. Он же залочится до тех пор пока кто-то по другой строке его не разбудит.

Ну а в случае с обычной синхронизацией (через синхронайз) что произойдет? Это по моему общая проблема
...
Рейтинг: 0 / 0
Синхронизация по String
    #37736541
OOsalivan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
забыл никBlazkowiczА ещё вопрос, все ведь строки на одном локе висят. Тогда если две разных строки в 2х потоках уже существуею, они ещё и с друг другом будут бодаться за lock?
И ещё вопрос к коду. Как отработает re-entrancy, если метод вызовется для той же строки, но в том же потоке?

Вот именно поэтому я и говорю, что надо использовать ReentrantLock, причем он должен быть не глобальным, а содержаться в Map

Так какую проблему решает ReentrantLock по отношению к Object.wait ?
Object.wait просто переводит поток в состояние ожидания, и из- за того что этот метод релизит монитор после перевода, то может использоваться сколько угодно
...
Рейтинг: 0 / 0
Синхронизация по String
    #37737086
wessen
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
shainsky
Я придумал такой код, но есть подозрения в том, что он неоптимален:

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
 

    static ConcurrentMap<String, String> workWith = new ConcurrentHashMap<String, String>();
         ...
        
    void someMethod(String s) {

        String current = workWith.putIfAbsent(s, s);
        if (current == null)
            current = s;
        synchronized (current) {

         // синхронизированный код ...

            workWith.remove(s);
        }
    }



Строка workWith.remove(s); лишняя, в случае, если потоков будет больше двух и они параллельно будут вызывать этот метод, то есть вероятность, что второй и третий потоки зайдут одновременно в синхронизированный блок.
...
Рейтинг: 0 / 0
36 сообщений из 36, показаны все 2 страниц
Форумы / Java [игнор отключен] [закрыт для гостей] / Синхронизация по String
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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