Java: Mám neprázdný Set, ale nemůžu z něj dostat položky

perceptron

Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
« Odpověď #15 kdy: 12. 04. 2018, 20:45:06 »
neni calendar nejaka proxy ktora loaduje veci z databazy? ako to robi hibernate?

ked vy volate imagesqueue tak sa queryuje databaza?


Kit

Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
« Odpověď #16 kdy: 12. 04. 2018, 21:20:04 »
Ale špatná synchronizace přístupu při změně té fronty by neměla vést k trvalé nepoužitelnosti té fronty, ne? Takže jeden problém je, zda je synchronizace v pořádku a druhý problém je, jakto že se ta fronta dostane do nevalidního stavu (není prázdná ale nemůžu dostat její prvky a to ani při pozastavených vláknech jvm).

Třída Iterate slouží k obalení (proxy) množiny. Množina obsahuje jeden element, ale třída Iterate ho z nějakého důvodu nevidí (hasNext()==false).

Třída LinkedHashSet není thread safe. Neměla by být obalena synchronizací při každé manipulaci?

Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
« Odpověď #17 kdy: 12. 04. 2018, 21:24:47 »
Může to být chybná deserializace nebo nějaká manipulace s privátními fieldy té třídy LinkedHashSet, případně nesyncrhonizovnaý přístup z více vláken a nebo se tam dostane null hodnota. HashMap (pomocí které je LinkedHashSet implementován), udržuje počet prvků v mapě jako samostatný field, který se při každé modifikaci mapy přepočítá. Podle mne se rozjede stav toho fieldu se skutečným stavem mapy.

Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
« Odpověď #18 kdy: 12. 04. 2018, 21:51:19 »
A link na ten Set má jenom ten Calendar?

Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
« Odpověď #19 kdy: 12. 04. 2018, 21:53:14 »
Ale špatná synchronizace přístupu při změně té fronty by neměla vést k trvalé nepoužitelnosti té fronty, ne? Takže jeden problém je, zda je synchronizace v pořádku a druhý problém je, jakto že se ta fronta dostane do nevalidního stavu (není prázdná ale nemůžu dostat její prvky a to ani při pozastavených vláknech jvm).

Třída Iterate slouží k obalení (proxy) množiny. Množina obsahuje jeden element, ale třída Iterate ho z nějakého důvodu nevidí (hasNext()==false).

Třída LinkedHashSet není thread safe. Neměla by být obalena synchronizací při každé manipulaci?

A o čem se tu asi bavíme?
Syncovat extra kvůli ní nemusíš, pokud syncuješ na tom kalendáři a on je jediný a jedinečný držitel reference na ten Set.


Kit

Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
« Odpověď #20 kdy: 12. 04. 2018, 22:01:03 »
Třída LinkedHashSet není thread safe. Neměla by být obalena synchronizací při každé manipulaci?

A o čem se tu asi bavíme?
Syncovat extra kvůli ní nemusíš, pokud syncuješ na tom kalendáři a on je jediný a jedinečný držitel reference na ten Set.

Nevím, o čem se bavíš ty, ale já se snažím najít důvod, proč mu u nesynchronizované třídy selhává synchronizace.

Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
« Odpověď #21 kdy: 12. 04. 2018, 22:18:55 »
A nevrací se buď přímo ten set nebo třeba jen iterátor někam mimo tu třídu, takže se k němu už přistupuje mimo synchronized? (teď nemyslím nutně ten testovací kód).

Jinak přelinkování objektů v HashSet/Map se může rozbít samo o sobě, pokud tam dělají dva thready něco zároveň, počítadla (včetně isEmpty()) to samozřejmě ještě zhorší.

A ano, ve chvíli, kdy se interní struktura rozbije jednou, tak se dohromady může dát už jenom stejnou (opačnou) náhodou (teď "mírně" zjednodušuju). Takže zůstane nejspíš rozbitá napořád.

Zkusil bych buď ConcurrentHashSet (tedy spíš zabalený Map) nebo Collections.synchronizedSet() ... Nebo spíš je otázka, proč něco, co se nazývá queue, je jenom Set a nikoliv (Blocking)Queue...

Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
« Odpověď #22 kdy: 12. 04. 2018, 22:42:01 »
Toto by mohla být odpověď na tvůj problém.

https://stackoverflow.com/questions/35444639/altering-hashcode-of-object-inside-of-hashset-hashmap

Pokud se ti změní hashcode objektu který je již v Setu chová se to takto divně. Podívej se jak je implementován HashSet.

Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
« Odpověď #23 kdy: 12. 04. 2018, 23:41:14 »
Pokud se ti změní hashcode objektu který je již v Setu chová se to takto divně. Podívej se jak je implementován HashSet.

Modifikace objektu (respektive jeho hashCode) rozbije jeho vyhledávání, ale nikoliv iteraci (nebo statistiku size a isEmpty). Tedy záleží na implementaci, můžou existovat takové, které rozbijí i iteraci, ale v java.util HashSet, LinkedHashSet i třeba TreeMap stále fungovat budou.

Youda

Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
« Odpověď #24 kdy: 13. 04. 2018, 01:09:18 »
No nevim, skoly nemam, ale pokud je dany set pouzit v concurrent prostredi, je nejaky duvod nepouzit Collections.synchronizedSet()?

Necetl jsem cely thread ale mozna je problem popsan zde
https://stackoverflow.com/questions/39334217/skip-synchronization-when-iterating-over-a-linkedhashset-and-no-remove-is-done

Lopata

Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
« Odpověď #25 kdy: 13. 04. 2018, 02:15:29 »
A co to tedy prostě oddebugovat?

Javista

Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
« Odpověď #26 kdy: 13. 04. 2018, 08:45:59 »
Mám v javě

Kód: [Vybrat]
package cz.exambuilder.entity.domain.calendar;
(...)
public class Calendar {
    protected static final Set<Image> imagesQueue = new LinkedHashSet<>();
    (...)
}

Je potřeba pohlídat že je důsledně zajištěno že do imagesQueue nikdy nebude přistupovat více threadů zároveň! Vzhledem k tomu že jde o statickou proměnnou tak se tato chyba může stát velmi jednoduše. Doporučuji používat nástroje pro statickou analýzu kódu (např. FindBugs), ty takovéhle základní věci odhalují.

Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
« Odpověď #27 kdy: 13. 04. 2018, 08:56:22 »
Děkuju všem za příspěvky, tak to zatím vypadá, že je problém s tou synchronizací, která ten set skutečně rozbije.

Pokud nahradím synchronizované metody v Calendar (jsou nestatické, takže by se mělo synchronizovat přes instanci Calendar) synchronizovanými bloky přes uvnitř těch metod (kde synchronizuju přes třídu Calendar.class), tak to funguje i při masivně paralelním přístupu (udělal jsem na to test). Takže pokud to celé dobře chápu, tak tam musí být ve skutečnosti více instancí Calendar čili synchronizace přes instanci Calendar není dostačující.

Javista

Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
« Odpověď #28 kdy: 13. 04. 2018, 09:01:10 »
Děkuju všem za příspěvky, tak to zatím vypadá, že je problém s tou synchronizací, která ten set skutečně rozbije.

Pokud nahradím synchronizované metody v Calendar (jsou nestatické, takže by se mělo synchronizovat přes instanci Calendar) synchronizovanými bloky přes uvnitř těch metod (kde synchronizuju přes třídu Calendar.class), tak to funguje i při masivně paralelním přístupu (udělal jsem na to test). Takže pokud to celé dobře chápu, tak tam musí být ve skutečnosti více instancí Calendar čili synchronizace přes instanci Calendar není dostačující.

Samozřejmě že synchronizace přes instanci Calendar není dostačující pokud existuje více instancí Calendar - představte si co se stane když přes dvě instance Calendar zároveň přistupujete k té samé (protože statické) proměnné imagesQueue - to je jasný recept na rozbití vnitřního stavu LinkedHashSet!

Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
« Odpověď #29 kdy: 13. 04. 2018, 09:05:51 »
Mám v javě

Kód: [Vybrat]
package cz.exambuilder.entity.domain.calendar;
(...)
public class Calendar {
    protected static final Set<Image> imagesQueue = new LinkedHashSet<>();
    (...)
}

Je potřeba pohlídat že je důsledně zajištěno že do imagesQueue nikdy nebude přistupovat více threadů zároveň! Vzhledem k tomu že jde o statickou proměnnou tak se tato chyba může stát velmi jednoduše. Doporučuji používat nástroje pro statickou analýzu kódu (např. FindBugs), ty takovéhle základní věci odhalují.
Samozřejmě že synchronizace přes instanci Calendar není dostačující pokud existuje více instancí Calendar - představte si co se stane když přes dvě instance Calendar zároveň přistupujete k té samé (protože statické) proměnné imagesQueue - to je jasný recept na rozbití vnitřního stavu LinkedHashSet!

K imagesQueue se nikdo jiný než Calendar nedostane, je privátní a nemá getter ani setter. Takže by mělo stačit synchronizovat příslušné metody v Calendar. Chyba byla asi v tom, že jsem pouze přidal klíčové slovo synchronized k těm metodám - s vědomím toho, že Calendar je singleton, což ale asi neplatí, protože tam může být ve skutečnosti více ekvivalentních instancí (v terminologii frameworku se tomu ale říká singleton). Nechal jsem se tím označením zřejmě svést (ale musím to ještě ověřit).