Zobrazit příspěvky

Tato sekce Vám umožňuje zobrazit všechny příspěvky tohoto uživatele. Prosím uvědomte si, že můžete vidět příspěvky pouze z oblastí Vám přístupných.


Příspěvky - Ondrej Nemecek

Stran: 1 ... 61 62 [63] 64 65 ... 90
931
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).

Tomu se rika race condition. Brian Goetz napsal skvelou knizku https://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601. Je ted ve sleve za $15. Stalo by zato si ji precist nez delat zavery, ze kdyz neco modifikuju pres nekolik threadu bez synchronizace, tak to nemuzu rozbit. Proto jsem psal, ze si hrajes na Doug Lea

Aha, dobře, díky za vysvětlení příspěvku. Problém nebyla absence synchronizace, ale špatná synchronizace (přes špatný objekt). Závěry jsem nedělal, ptal jsem se a odpověď jsem dostal již na cca druhé stránce této diskuze, totiž že se rozjede počítadlo se skutečným počtem prvků. Tímto je téma de fakto vyčerpáno, z literatury jsem si stáhnul Java Concurrency in Practice. Za mě už v debatě končím, klidně tu ale pokračujte  :)

932
Bavit se o tom, ze kdyz to pouzivas mezi nekolika thready a hrat si na to, ze rozumis JMM a visibility vic nez Doug Lea je zcestny. Nejdriv to udelej safe - reading i writing. Jestli se modifikujou elementy kolekce, tak musi byt samozrejme synchronizovany pres stejny monitor.

Necetl jsem vsechny odpovedi

Nerozumím, na koho to je reakce? Jinak myslím, že problém je vyřešen a téma vyčerpáno.

Jestli se modifikujou elementy kolekce, tak musi byt samozrejme synchronizovany pres stejny monitor.
Jestli tím myslíte změny vnitřního stavu prvků kolekce, pak to není pravda – právě naopak, takové změny nesmí být synchronizovány přes stejný monitor, mohlo by dojít k uváznutí. Takové změny musejí být synchronizovány s ohledem na to, jak se s těmi objekty pracuje – většinou asi každý prvek bude mít svůj vlastní monitor. Je dokonce možné, že synchronizované vůbec být nemusí – pokud se s každým prvkem té kolekce pracuje jen v jednom vláknu.

Uvědomte si, že do kolekcí se dávají prvky typu Object, je tak nastavený i kontrakt kolekcí. Takže kolekci změny čehokoli, co je mimo Object, nezajímají. V Object je hashCode() a equals(), které pro změnu musí zůstat neměnné po celou dobu existence objektu v kolekci, bez toho by většina kolekcí fungovala špatně – i v jednovláknovém kódu. Nebo-li změny stavu objektu, které by vyvolaly změnu hashCode() nebo equals() by byly špatně i v jednovláknovém kódu a žádná synchronizace tomu nepomůže, a jakékoli jiné změny kolekci nezajímají, nedozví se o nich a tudíž nemusí být kvůli kolekci synchronizovány.

Pan Jirsák má pravdu, to lze snad těžko rozporovat.

Jenom doplnění - k modifikacím Image nedochází přímo u prvků té kolekce, může k nim dojít jen v jiných instancích stejné entity jinde v kódu (tj. jiná proměnná, jiné místo v paměti, stejné UUID entity a stejný záznam v databázi). V kolekci pak zůstane neaktuální verze entity (u entit se používá eager loading). Neaktuální verze v kolekci ale ničemu nevadí, protože za chvíli bude aplikací použita a z kolekce odstraněna (tak funguje daná aplikační logika). Později se již do kolekce načte čerstvá verze. V tomto schématu by tedy podle mě mohlo dojít v nejhorším k tomu, že by v kolekci byla stejná entita 2x (pokud by se modifikací změnila identita, k čemuž ale v použitím frameworku nedojde). Takže synchronizovat tento druh modifikace není potřeba.

933
Podle mě záleží, jak je nastaveno to mazání na zařízení, odkud se mazalo - v nastavení IMAPu se dá nastavit, aby se mail na serveru buď  hned smazal anebo se jen označil pro smazání, ale k jeho úplnému smazání aby došlo až časem (kdy, to je záleží také na nastavení).

Další možnost je, že server může při smazání mail sám přesunout do koše. Není to zrovna případ gmailu? Pohladal bych ten mail přes webové rozhraní gmailu, zda tam není třeba v koši. Tohle chování se tam dá tuším také nastavit, tentokrát v účtu gmailu (neověřeno).

No a nakonec v tom druhém zařízení, kde je ten mail stažený, je možno v offline režimu ten mail překopírovat do jiné složky, pak se připojit a synchronizovat, případně ten mail zase zkopírovat zpátky do původní složky, pokud by v původní složky zmizel a nová složka se na server nepřenesla nebo nezesynchronizovala (záleží na nastavení té složky a době vytvoření).

Poslední možností je si ten mail v offline režimu přeposlat, tím se překopíruje do odchozí pošty a při přepnutí do online režimu se pak odešle.

Jinak v offline i online režimu lze v závislosti na použitém klientovi celý mail uložit jako eml soubor (bude obsahovat všechny přílohy a lze jej pak kdykoli zase v jiném poštovním programu otevřít, dokonce aniž by v něm musel být nastavený jakýkoli poštovní účet). Určitě to umí třeba Thunderbird, ostatní poštovní klienti to budou mít podobně, nejhůř na tom budou asi poštovní klienti pro mobilní zařízení, tam hodně záleží, který program zrovna používáte.

934
Nejprve si musíte určit, co vlastně znamená, že se jedná o ten samý objekt. Ale pokud vám z toho vyjde, že jeden objekt (konkrétní místo v paměti) může v průběhu své životnosti představovat několik různých objektů (hashCode a equals zahrnují položky, které se mohou změnit), nebude vám to s většinou kolekcí fungovat.

Tohle ale s vícevláknovým přístupem nesouvisí. Vám ten vícevláknový přístup nejspíš rozbil vnitřní implementaci HashMapy použitou v tom LinkedHashSetu. To by modifikovatelné prvky kolekce nezpůsobily, ty by mohly způsobit nanejvýš to, že byste do kolekce nějaký prvek vložil, ale on by tam později nebyl, nebo byste do kolekce vložil prvek, ale později byste tam našel jiný.

Ano, akorát s tím vícevláknovým přístupem to přece jen asi trochu souvisí, i když volně - a to tak, že pokud sdílím takhle napříč aplikací objekty, je větší šance, že budou někde modifikovány (kvantitativní, nikoli kvalitativní souvislost).

Modifikace se položek se nicméně děje zcela vyjimečně a věřím, že framework implementuje equals, hashCode a compareTo rozumně (konkrétně identitu dělá podle UUID objektu a compare podle řadící anotace, hashCode teď nevím). Kolekce fungují a nanejvýš můžu mít v setu chvíli neaktualizovanou položku, což mi nevadí.

Mně teda ale hlavně překvapuje, pokud tam Ondřej ty iterátory normálně používá, že to nikdy nevypadlo na ConcurrentModificationException. Že je to jenom taková nouzová pojistka, která ve vícevláknovém prostředí nemusí fungovat správně, je jasné, ale že se to netrefilo nikdy… Předpokládám, že modifikace toho setu probíhala z jiných vláken, než která používala ten iterátor, takže prostě každé vlákno mělo svou lokální hodnotu počtu modifikací a nikdy se to nepotkalo.

Já sám iterátory v kódu přímo nepoužívám (mimo toho testovacího, který jsem zkopíroval z interaktivní vývojové konzole). Ten set je bokem mimo framework jen proto, abych z jiné větší kolekce, kterou framework již normálně managuje, vybral část a uložil do toho setu bokem. Z něho pak po jedné odebírám položky a když položky dojdou, tak to zopakuju a zase jej naplním. Pokud se zdrojová kolekce změní, provede se merge položek - položky odstraněné ze zdrojové kolekce zmizí i ze setu. LinkedHashSet je tam proto, aby tam byla každá položka jen jednou a pamatovalo se pořadí vložení. Operace nad setem jsou tedy remove(), clear() a add() bez použití iterátoru.

tady ale nebyl problém s prvky té kolekce, ale s tou kolekcí jako takovou.

Je to tak, skutečně se ten set dostal do nekonzistentního stavu - protože není thread safe a nezajistil jsem správnou synchronizaci. Původně jsem spíš myslel že bude problém v identitě prvků setu ale nakonec jsem s jistotou ověřil, že to je v té synchronizaci.

935
Získám tím sdílený stav.
Získáte tím stav sdílený mezi jedním singletonem. To je trošku nesmysl, ne? A je to přesně to, co vás vypeklo – že jste jeden singleton měl z poloviny udělaný jedním způsobem a z poloviny druhým.

Ano, proto by skutečně dávalo smysl tu funkčnost vytáhnout bokem jak uvádí Zdenek Henek Tam bych si mohl i sám řešit, zda to je tvrdý singleton nebo ne - aniž by na to měl vliv framework (tj. bylo by to vyčlenění kompetence). Co mi ještě není úplně jasné je, čemu se vystavuju, pokud bych vracel ven měnitelné položky toho setu (neobalil je jak uvádí Zdenek Henek)? Pokud se podívám, jak framework implementuje hashCode, compareTo a equals, neměl bych v kolekcích ani při modifikaci narazit na problém. Je to tak? Resp. se to asi dočtu v té kapitole Publication and escape v Java Concurrency in Practice.

936
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).

Takže je to skutečně tak, že těch instancí Calendar je tam spousta (ale jsou identické - equals vrací true). To je asi ponaučení, co si odnáším a pak taky Javistovo shrnutí:

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.

Ani omylem! I kdyby zrovna teď platilo že víc instanci Calendar v aplikaci nevzniká, do budoucna se to může změnit a pak se to rozbije. Přístup ke statické instanci LinkedHashSet musí být chráněný jedním jediným mutexem a to klíčové slovo synchronized u nestatické metody nezajišťuje. Klasické řešení by bylo použít synchronized(imagesQueue) nebo rovnou v imagesQueue mít Collections.synchronizedSet(new LinkedHashSet()). Případně s ohledem na to že se proměnná jmenuje Queue použít úplně jinou třídu.

Tímto všem děkuji za angažmá a považuju to za vyřešené :-)

937
... s vědomím toho, že Calendar je singleton, ...

Proč je Calendar singleton? Copak není možné mít více kalendářů? Vidím to na nesmyslně použitý návrhový vzor.

Právě že to není návrhový vzor, ale způsob, jak se frameworku řekne, že tenhle objekt tam je právě jednou a že si uživatel nemá udělat kopii. Popletení těch významů je příčinou mého problému.

938
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.

Ještě si prosím nastudujte co přesně znamená klíčové slovo protected - rozhodně není vhodné ve spojení s ním používat výraz privátní, to je velmi zavádějící!

Změnil jsem to na private.

939
Navíc takovéhle použití statického fieldu je bad practice, nic tím nezískáte a akorát si zavíráte dveře – nebudete moci ten objekt pořádně testovat, bude špatně spolupracovat s frameworky atd.
Získám tím sdílený stav.

940
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).

941
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í.

942
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).

943
Nevím. Jsou ty Image mutable nebo volatile?

Mutable - Image jsou mutable (můžou se měnit).

Volatile - ta imagesQueue není volatile a co se týče referencí na jednotlivé Image si nejsem jist (položky imagesQueue získává framework).

944
Ten main synchronizovany nevidim. Zda ti debugger zastavi vsechny thready neni jiste. To se musis ujistit v dokumentaci sveho debuggeru.

Zastaví všechno, mám to nastavený u breakpointu. Ta imagesQueue se mění v metodách Calendar, ty metody jsou synchronizované, takže se synchronizují přes instanci Calendar. Ta by měla být jen jedna, protože Calendar je singleton. Ale napadá mě, že není jisté, co tím singletonem framework Brightspot má na mysli, protože to, že je Calendar singleton zajišťuje nějak interně framework. Možná ale nění   zajištěno, že bude vše doslova jediná instance. To by mohl být zdroj problému. Tahle varianta se mi zdá čím dál tím pravděpodobnější.

Aktuální podoba testu:

Kód: [Vybrat]
import cz.exambuilder.entity.domain.calendar.Calendar;
import java.util.stream.*;
import java.lang.reflect.*;
import org.slf4j.*;

public class Code {
    public static Object main() throws Throwable {

        Calendar calendar = Query.from(Calendar.class).first();

        synchronized(calendar){
            Logger log = LoggerFactory.getLogger(Code.class);
   
            // tady získám tu privátní instanci imagesQueue, abych se na ní mohl podívat:
   
            Field field = Calendar.class.getDeclaredField("imagesQueue");
            field.setAccessible(true);
            Set<Image> imagesQueue = (Set<Image>) field.get(calendar);
            // imagesQueue.clear();
            Iterator imagesIterator = imagesQueue.iterator();
   
            // tady zkouším, co imagesQueue obsahuje:
   
            log.info("*** calendar.getPresenationImages(1)" + calendar.getPresenationImages(1).size());
            log.info("*** imagesQueue.isEmpty(): " + imagesQueue.isEmpty()); // false
            log.info("*** imagesQueue.size(): " + imagesQueue.size()); // 1
            log.info("*** imagesQueue.stream(): " + imagesQueue.stream().map(i -> String.format("%s (%s)", i.getTitle(), i.getId())).collect(Collectors.toList())); // prázdná kolekce
            log.info("*** imagesIterator.hasNext(): " + imagesIterator.hasNext()); // false
        }
       
        return "SEE LOGS";

    }
}

945
Kód: [Vybrat]
imagesQueue.iterator().hasNext(); // dává false
imagesQueue.iterator().next(); //  hodí java.util.NoSuchElementException.

Na těchto dvou řádcích vytváříš dva různé objekty třídy Iterate, s každým manipuluješ zvlášť. Pokud máš podobná zvěrstva i jinde v kódu, tak se není čemu divit, že ti občas nějaký souběh něco poničí.

Samozřejmě že nedělám, každopádně meritem problému je že isEmpty je false a iterator().hasNext() je taky false. A jak k tomu problému jednou dojde, tak je už trvalý.

Děláš. Každé volání imagesQueue.iterator() vytváří novou instanci třídy Iterator. Takže je to i lenošnější, než by mohlo být.

Ano, Kite, to já vím. Snažil jsem se jen sdělit, že tento druh zvěrstev jinde v kódu nemám. To spíš blbne ta synchronizace.
Kite, tohle já vím. Snažil jsem se vysvětlit, že tento druh zvěrstev jinde v kódu nemám. To tam možná spíš blbne ta synchronizace.

Stran: 1 ... 61 62 [63] 64 65 ... 90