Fórum Root.cz

Hlavní témata => Vývoj => Téma založeno: Ondrej Nemecek 12. 04. 2018, 17:45:28

Název: Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondrej Nemecek 12. 04. 2018, 17:45:28
Takže nevím, zda je root ideální server pro tento dotaz, ale zkusím to  :)

Mám v javě

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

a ten set imagesQueue je neprázdný:

Kód: [Vybrat]
imagesQueue.isEmpty(); // dává false
imagesQueue.size(); // dává 1

Problém je, že položky toho setu nemůžu získat:

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

Podstatné, že k tomuto stavu dojde až po cca měsíčním běhu aplikace, zprvu to funguje normálně.

Čichal bych tady nějaký problém v implementaci equals(), hashCode() nebo compareTo(), ale na nic jsem nepřišel, používám výchozí implementace z frameworku. Možná vstoupí do hry nějaký JIT nebo přesun instancí do jiné oblasti paměti a změní se hashcode nebo něco podobného? Na co se mám zaměřit? Uvažoval jsem ještě nad tím, zda se to do tohoto stavu nemůže dostat špatně ošetřeným konkurenčním přístupem, ale nedokážu si to představit.

Pozitivní je, že mám k dispozici testovací prostředí, kde to ještě funguje i prostředí, kde to už nefunguje - do obou se můžu se připojit debuggerem nebo z vývojové konzole umožňující spouštět interaktivně kód.

Na co se mám zaměřit? Kdy k něčemu takovému může v principu vůbec dojít?

Používám java version "1.8.0_161", apache-tomcat-8.5.5, Debian 4.8.4-1 a Brightspot (https://github.com/perfectsense/brightspot-cms) ve verzi v3.2.7178-2110f8

Aktuální testovací kód:

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 {

        Logger log = LoggerFactory.getLogger(Code.class);

        // tady získám tu privátní instanci imagesQueue, abych se na ní mohl podívat:

        Calendar calendar = Query.from(Calendar.class).first();
        Field field = Calendar.class.getDeclaredField("imagesQueue");
        field.setAccessible(true);
        Set<Image> imagesQueue = (Set<Image>) field.get(calendar);

        // tady zkouším, co imagesQueue obsahuje:

        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("*** imagesQueue.iterator().hasNext(): " + imagesQueue.iterator().hasNext()); // false

        try {
           log.info("*** imagesQueue.iterator().next(): " + imagesQueue.iterator().next()); // NoSuchElementException
        } catch(Exception e){
            log.info("*** exception: " + e);
        }
       
        return "SEE LOGS";

    }
}

Dík za nápady!
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Kit 12. 04. 2018, 18:13:46
Kód: [Vybrat]
Iterator it = imagesQueue.iterator();
if (it.hasNext()) {
    System.out.println(it.next());
}

Řetězení se občas nevyplácí.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Phi 12. 04. 2018, 18:26:40
Nevím. Jsou ty Image mutable nebo volatile?
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondra Satai Nekola 12. 04. 2018, 18:29:03
Jak vis, ze ti do te fronty mezi tim nehrabe nekdo jiny?
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Kit 12. 04. 2018, 18:43:55
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čí.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondrej Nemecek 12. 04. 2018, 19:19:26
Kód: [Vybrat]
Iterator it = imagesQueue.iterator();
if (it.hasNext()) {
    System.out.println(it.next());
}

Řetězení se občas nevyplácí.
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ý.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondrej Nemecek 12. 04. 2018, 19:33:52
Jak vis, ze ti do te fronty mezi tim nehrabe nekdo jiny?

Pokud myslíš počas toho testu, tak například tak, že se připojím debuggerem, zastavím na breakpointu, který pauzne celou jvm a pak si v vyhodnotím příkazy imagesQueue.isEmpty(); imagesQueue.iterator().hasNext(); To by mělo být jisté, že do toho nikdo nehrabe, ne?

Pokud myslíš po celou dobu běhu aplikace, pak tam určitě hrabe víc vláken, modifikace se dějí v několika metodách třídy Calendar a ty metody jsou synchronizované, takže by se měly synchronizovat přes tu instanci Calendar. Pak můžu i v testu dát synchronizovaný blok přes tu instanci Calendar a mělo by to být taky košer, nebo ne?
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondra Satai Nekola 12. 04. 2018, 19:46:30
Ten main synchronizovany nevidim. Zda ti debugger zastavi vsechny thready neni jiste. To se musis ujistit v dokumentaci sveho debuggeru.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Kit 12. 04. 2018, 19:47:30
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.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondra Satai Nekola 12. 04. 2018, 19:51:07
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.

To tady fakt neni jadro problemu. Je to spatny styl, ale i kdyby tam to druhe volani nebylo, tak je tam porad problem.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondrej Nemecek 12. 04. 2018, 19:51:35
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.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Kit 12. 04. 2018, 19:52:44
Co takhle to udělet bez iterátoru? Stejně je tam zbytečný.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondrej Nemecek 12. 04. 2018, 20:00:28
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";

    }
}
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondrej Nemecek 12. 04. 2018, 20:10:13
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).
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondrej Nemecek 12. 04. 2018, 20:42:44
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).
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: perceptron 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?
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Kit 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?
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Filip Jirsák 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.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondra Satai Nekola 12. 04. 2018, 21:51:19
A link na ten Set má jenom ten Calendar?
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondra Satai Nekola 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.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Kit 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.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: kvr kvr 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...
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondřej Vaniš 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.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: kvr kvr 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.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Youda 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
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Lopata 13. 04. 2018, 02:15:29
A co to tedy prostě oddebugovat?
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Javista 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í.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondrej Nemecek 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í.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Javista 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!
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondrej Nemecek 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).
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Javista 13. 04. 2018, 09:18:55
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.

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.

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

Používat frameworky bez jejich znalosti je cesta do pekel.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Javista 13. 04. 2018, 09:21:37
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í!
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Kit 13. 04. 2018, 09:34:49
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í!

Všechny atributy objektu mají být private, jinak si vývojář koleduje o průšvih.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Filip Jirsák 13. 04. 2018, 09:35:01
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).
To použití je špatné tak jako tak. Pokud ten objekt má být singleton na zodpovědnost uživatele („není důvod mít víc instancí, ale když vzniknou, nemělo by to ničemu vadit“), má mít ten set jako instanční proměnnou. Pokud to má být tvrdý singleton (nesmí existovat víc kopií), musíte v kódu zajistit, aby to opravdu nemohlo nastat. 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.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Kit 13. 04. 2018, 09:46:57
... 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.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondrej Nemecek 13. 04. 2018, 10:10:05
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.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondrej Nemecek 13. 04. 2018, 10:11:13
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.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondrej Nemecek 13. 04. 2018, 10:14:51
... 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.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondrej Nemecek 13. 04. 2018, 10:23:00
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é :-)
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Zdenek Henek 13. 04. 2018, 10:30:37
Takže nevím, zda je root ideální server pro tento dotaz, ale zkusím to  :)

Mám v javě

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

a ten set imagesQueue je neprázdný:

Kód: [Vybrat]
imagesQueue.isEmpty(); // dává false
imagesQueue.size(); // dává 1

Problém je, že položky toho setu nemůžu získat:

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

Podstatné, že k tomuto stavu dojde až po cca měsíčním běhu aplikace, zprvu to funguje normálně.

Čichal bych tady nějaký problém v implementaci equals(), hashCode() nebo compareTo(), ale na nic jsem nepřišel, používám výchozí implementace z frameworku. Možná vstoupí do hry nějaký JIT nebo přesun instancí do jiné oblasti paměti a změní se hashcode nebo něco podobného? Na co se mám zaměřit? Uvažoval jsem ještě nad tím, zda se to do tohoto stavu nemůže dostat špatně ošetřeným konkurenčním přístupem, ale nedokážu si to představit.

Pozitivní je, že mám k dispozici testovací prostředí, kde to ještě funguje i prostředí, kde to už nefunguje - do obou se můžu se připojit debuggerem nebo z vývojové konzole umožňující spouštět interaktivně kód.

Na co se mám zaměřit? Kdy k něčemu takovému může v principu vůbec dojít?

Používám java version "1.8.0_161", apache-tomcat-8.5.5, Debian 4.8.4-1 a Brightspot (https://github.com/perfectsense/brightspot-cms) ve verzi v3.2.7178-2110f8

Aktuální testovací kód:

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 {

        Logger log = LoggerFactory.getLogger(Code.class);

        // tady získám tu privátní instanci imagesQueue, abych se na ní mohl podívat:

        Calendar calendar = Query.from(Calendar.class).first();
        Field field = Calendar.class.getDeclaredField("imagesQueue");
        field.setAccessible(true);
        Set<Image> imagesQueue = (Set<Image>) field.get(calendar);

        // tady zkouším, co imagesQueue obsahuje:

        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("*** imagesQueue.iterator().hasNext(): " + imagesQueue.iterator().hasNext()); // false

        try {
           log.info("*** imagesQueue.iterator().next(): " + imagesQueue.iterator().next()); // NoSuchElementException
        } catch(Exception e){
            log.info("*** exception: " + e);
        }
       
        return "SEE LOGS";

    }
}

Dík za nápady!

Nepouzivejte plain Set jak static promenou.

Zabalte to do nejake tridy a pak bud vse synchrnonizujte, nebo at  veskere operace v metode nemeni tu mnozinu.

e.g.

class MySet{
.....
  MySet(Set<Image> a){
    this.a = new HashSet(a);
  }

  ... metody pro praci s tou mnozinou...
  tu mnozinu nepoustejte ven z tohoto objektu

  pokud budete predavat objekty z te mnoziny ven, musite zajistit ze budou nemenne, nebo opet obalte obalovou tridou a synchronizujte. Vice v Concurrency in Practice strana 39, Publication and escape.
}

Jako bonus toto Vam pomuze udrzovat kod, ktery nejak manipuluje s tou mnozinou na jednom miste.

Jetse me tak napada, ze byste mohl spis pouzivat neco jako https://github.com/ben-manes/caffeine at Vam tam ty obrazky nevytvari memory leak a po case je vyhazovat. Jetsli teda mate moznost si ty obrazky opet vytvorit, kdyz uz nebudou v te mnozine.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Filip Jirsák 13. 04. 2018, 10:33:33
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.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Kit 13. 04. 2018, 10:51:50
Nepouzivejte plain Set jak static promenou.

Zabalte to do nejake tridy a pak bud vse synchrnonizujte, nebo at  veskere operace v metode nemeni tu mnozinu.

Ano, přesně takhle se to má dělat.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondrej Nemecek 13. 04. 2018, 14:38:54
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 (https://forum.root.cz/index.php?topic=18205.msg260563#msg260563) 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.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Zdenek Henek 13. 04. 2018, 15:20:24
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 (https://forum.root.cz/index.php?topic=18205.msg260563#msg260563) 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.

Pokud mate synchronizovane oprace nad Set<...> tak to nestaci pokud neco co je v te Set pustite mimo synchronized sekci a pak to tam menite. Musite zajistit, ze se to bud nebude menit - nejlepsi, nebo ze veskere zmeny budou opet synchronizovane.

Jestli muzu doporucit, poridte si tu knihu Java Concurrency in practice. Nebojte se, ze je z roku 2006, jedine, co tam nenajdete jsou nove veci implementovane pozdeji, ale zakladni princip Vasi otazky tam je moc dobre popsany.

Pochybuju ze objectk Image je immutable, pokud je, tak nemusite nic delat. Immutable, znamena, ze bez reflexe se s tim neda nic delat, ne ze si slibite, ze to nebudete menit, protoze na to zapomenete. Jeste muzete pred kazdou modifikaci udelat clon toho objektu a po provedeni zmen vyhodit ze Set objektu ten stary a dat tam novy ... , ale to je cesta do pekel. Pak je clone na kazdem rohu.

Nejjednodussi pravidlo je, ze cokoli je sdilene je immutable a ma to builder. Pokud to nejde, tak wrapper a synchronizace.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Filip Jirsák 13. 04. 2018, 15:33:01
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)?
To není úplně přesné. Java collections framework má nějaké požadavky na položky, které se do kolekcí vkládají – na hashCode, equals a compare. Respektive dokonce každá implementace kolekcí může mít ty požadavky trochu jiné. Podstatné je splnění těch požadavků. Lapidárně řečeno, objekt se může měnit, jak chce, ale dokud bude mít stejný hashCode a bude správně odpovídat na equals, je to v pořádku.

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.
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ý.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Filip Jirsák 13. 04. 2018, 15:44:43
Pokud mate synchronizovane oprace nad Set<...> tak to nestaci pokud neco co je v te Set pustite mimo synchronized sekci a pak to tam menite. Musite zajistit, ze se to bud nebude menit - nejlepsi, nebo ze veskere zmeny budou opet synchronizovane.
Pokud ty změny neovlivní hashCode() a equals(), tak je tomu Setu úplně jedno, že se ten objekt mění mimo kód synchronizovaný pro tu práci se Setem. Ostatně, ten Set ani nic jiného než referenci na ten objekt a jeho hash kód nezná. něco jiného je, že je divné v nesynchronizovaném kódu měnit sdílené objekty, pak můžete vidět v každém vlákně jiný stav toho objektu – ale to není problém toho Setu. Ale ty změny klidně mohou být synchronizovány jinak, nezávisle na tom Setu (naopak je to tak správně, synchronizovat se má vždy co nejmenší blok kódu a zamykat co nejméně věcí, a nechcete zbytečně zamykat Set, když plánujete jenom změnit field jedné položky v tom Setu).

A naopak, pokud změny v tom objektu změní hashCode() nebo i jen equals(), pak to chování toho Setu rozbije i v jednovláknovém kódu, se synchronizací to nijak nesouvisí.

Nejjednodussi pravidlo je, ze cokoli je sdilene je immutable a ma to builder.
A nejjednodušší builder je konstruktor a immutable zajistí final fieldy. Pak vám to pohlídá i kompilátor, že ten objekt nejde změnit ani zevnitř.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Zdenek Henek nereg. 13. 04. 2018, 16:00:52
Pokud mate synchronizovane oprace nad Set<...> tak to nestaci pokud neco co je v te Set pustite mimo synchronized sekci a pak to tam menite. Musite zajistit, ze se to bud nebude menit - nejlepsi, nebo ze veskere zmeny budou opet synchronizovane.
Pokud ty změny neovlivní hashCode() a equals(), tak je tomu Setu úplně jedno, že se ten objekt mění mimo kód synchronizovaný pro tu práci se Setem. Ostatně, ten Set ani nic jiného než referenci na ten objekt a jeho hash kód nezná. něco jiného je, že je divné v nesynchronizovaném kódu měnit sdílené objekty, pak můžete vidět v každém vlákně jiný stav toho objektu – ale to není problém toho Setu. Ale ty změny klidně mohou být synchronizovány jinak, nezávisle na tom Setu (naopak je to tak správně, synchronizovat se má vždy co nejmenší blok kódu a zamykat co nejméně věcí, a nechcete zbytečně zamykat Set, když plánujete jenom změnit field jedné položky v tom Setu).

A naopak, pokud změny v tom objektu změní hashCode() nebo i jen equals(), pak to chování toho Setu rozbije i v jednovláknovém kódu, se synchronizací to nijak nesouvisí.

Nejjednodussi pravidlo je, ze cokoli je sdilene je immutable a ma to builder.
A nejjednodušší builder je konstruktor a immutable zajistí final fieldy. Pak vám to pohlídá i kompilátor, že ten objekt nejde změnit ani zevnitř.

Jeste je tu jedna moznost, ze pokud nejsou zmeny synchorinzovane, tak muze videt treba jen cast tech zmen.

Mate pravdu, ze nemenit nic co by zmenilo hashCode a equals je zaklad. Predpokladal jsem, ze toto neni ten problem, protoze to ze zacatku fungovalo a nahodne se to rozbiji, ale muze to byt i tim, ze kod, ktery meni vnitrni stav objektu byl pridan pozdeji, nebo nebyl pouzivany. Tim ze mame vse immutable, tak me toto ani nenapadlo. Jeste obcas mame problem s tim, ze objekt ma v sobe dalsi objekt a ten nema implementovany hashcode nebo equals. To je pak o nervy toto najit. Nenajde to ani Sonar, PMD, FindBugs ... a zda se, ze to nikomu nevadi, asi v kolekcich pouzivaji jen String..

Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Filip Jirsák 13. 04. 2018, 16:33:17
Mate pravdu, ze nemenit nic co by zmenilo hashCode a equals je zaklad. Predpokladal jsem, ze toto neni ten problem, protoze to ze zacatku fungovalo a nahodne se to rozbiji, ale muze to byt i tim, ze kod, ktery meni vnitrni stav objektu byl pridan pozdeji, nebo nebyl pouzivany.
tady ale nebyl problém s prvky té kolekce, ale s tou kolekcí jako takovou.

Ale vzhledem k tomu, že LinkedhashSet je implementováno pomocí HashMap, a HashMap má field int size a metody

Kód: [Vybrat]
public int size() {
  return size;
}

public boolean isEmpty() {
 return size == 0;
}

je jasné, že si HashMapa (logicky) udržuje počet položek nezávisle na skutečném obsahu mapy. A tudíž je zřejmé, že se při nesynchronizovaném přístupu může rozejít stav „počítadla“ size se skutečným stavem mapy. Iterátor pak už samozřejmě musí jít do samotné mapy, kde zjistí, že tam ve skutečnosti nic není. Taky mohl Ondřej  skončit ve stavu, že by mu size() vracelo zápornou hodnotu… isEmpty() by bylo pořád false, a iterátor by klidně mohl nějaké hodnoty vracet.

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.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: kvr kvr 13. 04. 2018, 16:59:45
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.

Je otázka, jak často iterator běhal ve srovnání s modifikacemi. Nicméně obecně, ConcurrentModificationException se detekuje podle počítadla modifikací a ten, než se zpropaguje z jednoho CPU cache do druhého, tak už je typicky dávno po iteraci...
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondrej Nemecek 13. 04. 2018, 19:01:25
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.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Karel Rank 14. 04. 2018, 03:23:09
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
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Filip Jirsák 14. 04. 2018, 09:01:17
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.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondrej Nemecek 14. 04. 2018, 15:35:41
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.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Kit 14. 04. 2018, 16:14:15
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.

To je fakt tak těžké si obalit kolekci proxy vrstvou, která synchronizovaně zajistí všechny potřebné služby Image a nepřipustí přímou manipulaci s kolekcí?
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Karel Rank 14. 04. 2018, 18:22:53
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.

Proc se bavime o single thread? Proc by melo dojit k uvaznuti (asi deadlock?)? Jak todle resi Collections.synchornized*? Jak happened-before je reseno v SynchronousQueue a Executors Framework?

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.

Ne, do kolekce se nedavaji Object. Davaji se tam jakykoliv tridy. U jakych kolekci je takhle nastavenej konktrakt (ja to vim)? Takze podle tvoji logiky nesmim menit zadny objekt, ktery je v kolekci? To by bylo asi hodne omezeny pouziti :)
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Filip Jirsák 14. 04. 2018, 18:48:25
Proc se bavime o single thread?
V té části, kterou jste citoval, se bavíme o multihtread.

Proc by melo dojit k uvaznuti (asi deadlock?)?
Protože se jedním zámkem pokrývají dvě nesouvisející operace. Ale je pravda, že to samo k uváznutí nepovede, k tomu jsou potřeba dva zámky.

Jak todle resi Collections.synchornized*?
Řeší to správně, synchronizují jen kolekce a o jednotlivé prvky kolekcí se nestarají.

Jak happened-before je reseno v SynchronousQueue a Executors Framework?
Pomocí běžných synchronizačních primitiv, které jsou v Javě dostupné.

Ne, do kolekce se nedavaji Object. Davaji se tam jakykoliv tridy.
Ne, do kolekcí se nedávají třídy, dávají se tam instance. Přičemž rozhraní kolekcí vyžaduje, aby to byly instance třídy Object, tedy od těch instancí nemohou vyžadovat žádné zvláštní chování nad rámec třídy Object.

U jakych kolekci je takhle nastavenej konktrakt (ja to vim)?
hashCode() překvapivě u kolekcí, které používají hash objektu, tedy všechny kolekce, které mají v názvu „Hash“, s výjimkou identityHashMap. equals() u všech kolekcí, pokud není řečeno jinak – přičemž pokud vím, jinak je to u kolekcí v JDK pouze (opět) u IdentityHashMap, která používá identitu objektů, nikoli equals().

Takze podle tvoji logiky nesmim menit zadny objekt, ktery je v kolekci? To by bylo asi hodne omezeny pouziti :)
Ne, psal jsem pravý opak, že prvky v kolekci se mohou modifikovat libovolně, pokud to neovlivní hashCode() nebo equals().
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Karel Rank 14. 04. 2018, 19:05:51
Proc se bavime o single thread?
V té části, kterou jste citoval, se bavíme o multihtread.
Single thread si do toho zamotal ty.

Proc by melo dojit k uvaznuti (asi deadlock?)?
Protože se jedním zámkem pokrývají dvě nesouvisející operace. Ale je pravda, že to samo k uváznutí nepovede, k tomu jsou potřeba dva zámky.
Takze, kdyz nactu z ConcurrentHashMap prvek, zmenim ho a dam ho zpatky (se stejnym klicem), zajistil jsem viditelnost zmen v jinych trehaded nebo ne? Muzu zmenit ten prvek (ne klic)?

Jak todle resi Collections.synchornized*?
Řeší to správně, synchronizují jen kolekce a o jednotlivé prvky kolekcí se nestarají.
Staraji. Kazdy volani zajistuje uplatneni happened-before.

Jak happened-before je reseno v SynchronousQueue a Executors Framework?
Pomocí běžných synchronizačních primitiv, které jsou v Javě dostupné.
Prave. Kdyz neco pridam do fronty, tak vsechny zmeny udelany predtim (i tech prvku), tak se uplatni.

Ne, do kolekce se nedavaji Object. Davaji se tam jakykoliv tridy.
Ne, do kolekcí se nedávají třídy, dávají se tam instance. Přičemž rozhraní kolekcí vyžaduje, aby to byly instance třídy Object, tedy od těch instancí nemohou vyžadovat žádné zvláštní chování nad rámec třídy Object.
:)
U jakych kolekci je takhle nastavenej konktrakt (ja to vim)?
hashCode() překvapivě u kolekcí, které používají hash objektu, tedy všechny kolekce, které mají v názvu „Hash“, s výjimkou identityHashMap. equals() u všech kolekcí, pokud není řečeno jinak – přičemž pokud vím, jinak je to u kolekcí v JDK pouze (opět) u IdentityHashMap, která používá identitu objektů, nikoli equals().

Takze podle tvoji logiky nesmim menit zadny objekt, ktery je v kolekci? To by bylo asi hodne omezeny pouziti :)
Ne, psal jsem pravý opak, že prvky v kolekci se mohou modifikovat libovolně, pokud to neovlivní hashCode() nebo equals().
Takhle to nevyznelo. Ale beru opravu.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Karel Rank 14. 04. 2018, 19:08:46
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 (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
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Kit 14. 04. 2018, 19:27:05
Ne, do kolekce se nedavaji Object. Davaji se tam jakykoliv tridy. U jakych kolekci je takhle nastavenej konktrakt (ja to vim)? Takze podle tvoji logiky nesmim menit zadny objekt, ktery je v kolekci? To by bylo asi hodne omezeny pouziti :)

Do kolekce se nedávají třídy, ale objekty splnující deklarované rozhraní.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondrej Nemecek 14. 04. 2018, 19:32:31
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 (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  :)
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Karel Rank 14. 04. 2018, 19:34:49
Ne, do kolekce se nedavaji Object. Davaji se tam jakykoliv tridy. U jakych kolekci je takhle nastavenej konktrakt (ja to vim)? Takze podle tvoji logiky nesmim menit zadny objekt, ktery je v kolekci? To by bylo asi hodne omezeny pouziti :)

Do kolekce se nedávají třídy, ale objekty splnující deklarované rozhraní.

Napsal jsem to spatne. Todle je lepsi definice
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondrej Nemecek 14. 04. 2018, 19:36:55
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.

To je fakt tak těžké si obalit kolekci proxy vrstvou, která synchronizovaně zajistí všechny potřebné služby Image a nepřipustí přímou manipulaci s kolekcí?

Ne, ale proč to dělat? V daném případě to je úplně zbytečné. Taky se neptám, proč jedeš autobusem a ne vlakem, když „jet vlakem snad není tak těžké“. Jinými slovy, problém jsem opravil adekvátně k významu a rozsahu té aplikace a její funkčnosti. Tímto debatu končím a samozřejmě děkuju za příspěvky (jsem zvědavý na kolik stránek tu debatu ještě natáhnete, ale za mě to je uzavřené).
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Filip Jirsák 14. 04. 2018, 19:37:25
Single thread si do toho zamotal ty.
Psal jsem o modifikacích prvků kolekce, které jste do toho zamotal mimo jiné vy. A psal jsem, že se to dělí na dvě varianty. Buď modifikace, které nemají vliv na hashCode() a equals() – takové modifikace kolekci vůbec nezajímají, takže není potřeba řešit žádnou synchronizaci. A nebo modifikace prvku, která má vliv na hashCode() a equals() – taková modifikace by byla pro hashovanou kolekci problém i v jednovláknovém prostředí, takže synchronizace by ničemu nepomohla.

Takze, kdyz nactu z ConcurrentHashMap prvek, zmenim ho a dam ho zpatky (se stejnym klicem), zajistil jsem viditelnost zmen v jinych trehaded nebo ne? Muzu zmenit ten prvek (ne klic)?
Když vložíte do ConcurrentHashMap jinou hodnotu pod původní klíč, bude pod tím klíčem nová hodnota viditelná ze všech vláken. Ale to je speciální vlastnost ConcurrentHashMap, která je speciálně pro konkurenční přístup určená. Pokud jenom změníte nějaké vlastnosti hodnoty, s mapou to vůbec nijak nesouvisí (a pro hodnoty v mapě nejsou důležité ani metody hashCode() a equals()) – pokud se tou hodnotou má pracovat ve více vláknech, musí ty změny být synchronizované. ConcurrentHashMap tomu nijak nepomůže.

Staraji. Kazdy volani zajistuje uplatneni happened-before.
Nestarají. Synchronizovaná jsou pouze volání metod na těch kolekcích. Co se děje s prvky kolekce ty kolekce vůbec nezajímá.

Například v tomhle kódu vám to druhé vlákno může vypsat 0, 1 nebo i hodnotu, kterou měla ta položka ještě dříve.
Kód: [Vybrat]
Item item = synchronizedMap.get("item1");
item.setValue(0);
new Thread(() -> item.setValue(1)).start();
new Thread(() -> System.out.println(item.getValue())).start();

Prave. Kdyz neco pridam do fronty, tak vsechny zmeny udelany predtim (i tech prvku), tak se uplatni.
Což je ale dané tím, jak fungují paměťové bariéry. Není to žádná specialita synchronizovaných kolekcí, protože úplně stejně se to bude chovat i při jakémkoli jiném použití synchronizačních primitiv.

Takhle to nevyznelo. Ale beru opravu.

Mně zase jako pravý opak vyznělo to vaše tvrzení:

Citace: Karel Rank
Jestli se modifikujou elementy kolekce, tak musi byt samozrejme synchronizovany pres stejny monitor.
Proto jsem na to reagoval.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Karel Rank 14. 04. 2018, 19:40:26
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 (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ů.

Na jiny masine to muze vypadat jinak. Proto je to race condition. A je jedno jestli to je absenci synchronizace nebo spatny synchronizaci.

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  :)

Skvely! Doufam, ze stahnul = koupil  ;)
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Filip Jirsák 14. 04. 2018, 19:41:43
Do kolekce se nedávají třídy, ale objekty splnující deklarované rozhraní.
Přičemž v JVM v kolekcích z Java Collections Framework je to deklarované rozhraní vždy java.lang.Object. Od Javy 5 výš dělá kompilátor „kouzla“ s generiky, takže ve zdrojovém kódu může být deklarované jiné rozhraní, ale v class file jsou metody kolekcí pořád deklarované jako booleanadd(Object item).
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Karel Rank 14. 04. 2018, 19:47:08
Do kolekce se nedávají třídy, ale objekty splnující deklarované rozhraní.
Přičemž v JVM v kolekcích z Java Collections Framework je to deklarované rozhraní vždy java.lang.Object. Od Javy 5 výš dělá kompilátor „kouzla“ s generiky, takže ve zdrojovém kódu může být deklarované jiné rozhraní, ale v class file jsou metody kolekcí pořád deklarované jako booleanadd(Object item).

Neni to pravda :) https://docs.oracle.com/javase/10/docs/api/java/util/Collection.html#add(E) (https://docs.oracle.com/javase/10/docs/api/java/util/Collection.html#add(E))
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Karel Rank 14. 04. 2018, 19:53:58
Single thread si do toho zamotal ty.
Psal jsem o modifikacích prvků kolekce, které jste do toho zamotal mimo jiné vy. A psal jsem, že se to dělí na dvě varianty. Buď modifikace, které nemají vliv na hashCode() a equals() – takové modifikace kolekci vůbec nezajímají, takže není potřeba řešit žádnou synchronizaci. A nebo modifikace prvku, která má vliv na hashCode() a equals() – taková modifikace by byla pro hashovanou kolekci problém i v jednovláknovém prostředí, takže synchronizace by ničemu nepomohla.

Takze, kdyz nactu z ConcurrentHashMap prvek, zmenim ho a dam ho zpatky (se stejnym klicem), zajistil jsem viditelnost zmen v jinych trehaded nebo ne? Muzu zmenit ten prvek (ne klic)?
Když vložíte do ConcurrentHashMap jinou hodnotu pod původní klíč, bude pod tím klíčem nová hodnota viditelná ze všech vláken. Ale to je speciální vlastnost ConcurrentHashMap, která je speciálně pro konkurenční přístup určená. Pokud jenom změníte nějaké vlastnosti hodnoty, s mapou to vůbec nijak nesouvisí (a pro hodnoty v mapě nejsou důležité ani metody hashCode() a equals()) – pokud se tou hodnotou má pracovat ve více vláknech, musí ty změny být synchronizované. ConcurrentHashMap tomu nijak nepomůže.

Ne, to neni specialni vlastnost ConcurrentHashMap. To je vlastnost happens-before. Je to i u jinych kolekci, ktery jsou synchronized.

Staraji. Kazdy volani zajistuje uplatneni happened-before.
Nestarají. Synchronizovaná jsou pouze volání metod na těch kolekcích. Co se děje s prvky kolekce ty kolekce vůbec nezajímá.

Například v tomhle kódu vám to druhé vlákno může vypsat 0, 1 nebo i hodnotu, kterou měla ta položka ještě dříve.
Kód: [Vybrat]
Item item = synchronizedMap.get("item1");
item.setValue(0);
new Thread(() -> item.setValue(1)).start();
new Thread(() -> System.out.println(item.getValue())).start();

Jo, tendle kod je spatne.

Prave. Kdyz neco pridam do fronty, tak vsechny zmeny udelany predtim (i tech prvku), tak se uplatni.

Což je ale dané tím, jak fungují paměťové bariéry. Není to žádná specialita synchronizovaných kolekcí, protože úplně stejně se to bude chovat i při jakémkoli jiném použití synchronizačních primitiv.


Nahore si uvedl, ze to je specialiata ConcurrentHashMap. A ted ze to neni specialiata?
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Filip Jirsák 14. 04. 2018, 20:11:42
Ne, to neni specialni vlastnost ConcurrentHashMap. To je vlastnost happens-before. Je to i u jinych kolekci, ktery jsou synchronized.
Takže je to speciální vlastnost ConcurrentHashMap jako synchronizované kolekce, jak jsem napsal.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Karel Rank 14. 04. 2018, 20:17:49
Ne, to neni specialni vlastnost ConcurrentHashMap. To je vlastnost happens-before. Je to i u jinych kolekci, ktery jsou synchronized.
Takže je to speciální vlastnost ConcurrentHashMap jako synchronizované kolekce, jak jsem napsal.

lol
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Filip Jirsák 14. 04. 2018, 20:45:05
Do kolekce se nedávají třídy, ale objekty splnující deklarované rozhraní.
Přičemž v JVM v kolekcích z Java Collections Framework je to deklarované rozhraní vždy java.lang.Object. Od Javy 5 výš dělá kompilátor „kouzla“ s generiky, takže ve zdrojovém kódu může být deklarované jiné rozhraní, ale v class file jsou metody kolekcí pořád deklarované jako booleanadd(Object item).

Neni to pravda :) https://docs.oracle.com/javase/10/docs/api/java/util/Collection.html#add(E) (https://docs.oracle.com/javase/10/docs/api/java/util/Collection.html#add(E))

Proč se pouštíte do diskuse o něčem, čemu nerozumíte? Když napíšu, že v Java bytecode je to nějak a Java zdroják nad tím jenom dělá jakási cukrlátka, fakt není dobrý nápad napsat, že to není pravda a dokazovat to odkazem na JavaDoc, který popisuje právě ta cukrlátka v Java zdrojáku. Když se podíváte do bajtkódu, zjistíte, že tam je metoda opravdu definována jako java/util/Collection.add:(Ljava/lang/Object;)Z. A když si nastudujete něco o type erasure, pomocí kterého jsou implementovány generiky v Javě, pochopíte, proč je to tak v bajtcode. A pokud je bajtkód nad vaše síly, zkuste si to alespoň v Javě pomocí reflexe:
Kód: [Vybrat]
Method addMethod = java.util.Collection.class.getMethod("add", Object.class);Zkuste si tam místo Object.class dát jakoukoli jinou třídu, a uvidíte, zda takové metody existují…
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Karel Rank 14. 04. 2018, 21:22:01
Do kolekce se nedávají třídy, ale objekty splnující deklarované rozhraní.
Přičemž v JVM v kolekcích z Java Collections Framework je to deklarované rozhraní vždy java.lang.Object. Od Javy 5 výš dělá kompilátor „kouzla“ s generiky, takže ve zdrojovém kódu může být deklarované jiné rozhraní, ale v class file jsou metody kolekcí pořád deklarované jako booleanadd(Object item).

Neni to pravda :) https://docs.oracle.com/javase/10/docs/api/java/util/Collection.html#add(E) (https://docs.oracle.com/javase/10/docs/api/java/util/Collection.html#add(E))

Proč se pouštíte do diskuse o něčem, čemu nerozumíte? Když napíšu, že v Java bytecode je to nějak a Java zdroják nad tím jenom dělá jakási cukrlátka, fakt není dobrý nápad napsat, že to není pravda a dokazovat to odkazem na JavaDoc, který popisuje právě ta cukrlátka v Java zdrojáku. Když se podíváte do bajtkódu, zjistíte, že tam je metoda opravdu definována jako java/util/Collection.add:(Ljava/lang/Object;)Z. A když si nastudujete něco o type erasure, pomocí kterého jsou implementovány generiky v Javě, pochopíte, proč je to tak v bajtcode. A pokud je bajtkód nad vaše síly, zkuste si to alespoň v Javě pomocí reflexe:
Kód: [Vybrat]
Method addMethod = java.util.Collection.class.getMethod("add", Object.class);Zkuste si tam místo Object.class dát jakoukoli jinou třídu, a uvidíte, zda takové metody existují…

Ne, neni takhle definovana v bytecode. Je definovana jako


  public abstract boolean add(E);
    descriptor: (Ljava/lang/Object;)Z
    flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
    Signature: #28                          // (TE;)Z


Dulezita je signature.


 TypeVariableSignature:
    T Identifier ;


Citace
Java zdroják nad tím jenom dělá jakási cukrlátka

Takze compiler bez zrojaku nevi jak ma nahradit generics? Jak ma delat strong type checking, protoze vsechno je Object? Ta informace neni v bytecode?
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Filip Jirsák 14. 04. 2018, 21:54:29
Ne, neni takhle definovana v bytecode. Je definovana jako
Aha, budeme hrát najdete pět rozdílů. Nebo aspoň jeden:

(Ljava/lang/Object;)Z
(Ljava/lang/Object;)Z

Dulezita je signature.
Ne, není. To je jen doplňková informace pro kompilátor, JVM je to úplně ukradené.

Takze compiler bez zrojaku nevi jak ma nahradit generics? Jak ma delat strong type checking, protoze vsechno je Object? Ta informace neni v bytecode?
Pro nahrazování generik kompilátor ty rozšířené informace nepotřebuje, k tomu mu stačí raw typy. Aby mohl dělat strong type checking, jsou v class souboru doplněné ty typové informace navíc oproti bajtkódu, který zpracovává JVM. V raw typech nemusí být všechno objekt, je tam typ určený omezeními generik. Ty informace v class souboru jsou jako rozšířené atributy, které nepotřebuje JVM – podobně jako třeba ladicí informace (jména lokálních proměnných nebo čísla řádků).

A kolekce na tyhle rozšířené informace opravdu žádným způsobem nespoléhají. Ony kolekce byly součástí Javy už před Javou 5, a tehdy opravdu měly i ve zdrojáku jako parametr napsán typ Object. A protože rozhraní je stále zpětně kompatibilní, mají takový typ i dnešní raw kolekce.

Nechápu, proč si to nezjistíte sám, metodu Class.getMethods() snad znáte, takže všechny metody libovolného typu kolekce si můžete vypsat. Na třídě java.util.Collection těch metod add opravdu moc nenapočítáte, protože tam bude ta jedna jediná, která má jako parametr typ Object.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Karel Rank 14. 04. 2018, 22:29:54
Ne, neni takhle definovana v bytecode. Je definovana jako
Aha, budeme hrát najdete pět rozdílů. Nebo aspoň jeden:

(Ljava/lang/Object;)Z
(Ljava/lang/Object;)Z

Dulezita je signature.
Ne, není. To je jen doplňková informace pro kompilátor, JVM je to úplně ukradené.

Takze compiler bez zrojaku nevi jak ma nahradit generics? Jak ma delat strong type checking, protoze vsechno je Object? Ta informace neni v bytecode?
Pro nahrazování generik kompilátor ty rozšířené informace nepotřebuje, k tomu mu stačí raw typy. Aby mohl dělat strong type checking, jsou v class souboru doplněné ty typové informace navíc oproti bajtkódu, který zpracovává JVM. V raw typech nemusí být všechno objekt, je tam typ určený omezeními generik. Ty informace v class souboru jsou jako rozšířené atributy, které nepotřebuje JVM – podobně jako třeba ladicí informace (jména lokálních proměnných nebo čísla řádků).

A kolekce na tyhle rozšířené informace opravdu žádným způsobem nespoléhají. Ony kolekce byly součástí Javy už před Javou 5, a tehdy opravdu měly i ve zdrojáku jako parametr napsán typ Object. A protože rozhraní je stále zpětně kompatibilní, mají takový typ i dnešní raw kolekce.

Nechápu, proč si to nezjistíte sám, metodu Class.getMethods() snad znáte, takže všechny metody libovolného typu kolekce si můžete vypsat. Na třídě java.util.Collection těch metod add opravdu moc nenapočítáte, protože tam bude ta jedna jediná, která má jako parametr typ Object.

Samozrejme, ze kompilator ty rozsirene informace (jak tomu rikas) potrebuje pro generics erasure. Musi vedet, co ma nahradit, jestli to splnuje podminky (? extends F00b4r) etc... Takze to je soucasti definice metody v bytecode. To ze se nahrazujou unbounded typy Object na tom nic nemeni. Urcite vis proc to je zrovna Object.

Pokazdy, kdyz ti vyvratim tvoje tvrzeni, tak prijdes s necim jinym. Od bytecode definition (kde si dal neuplnou informaci), k tomu jestli JVM potrebuje singatures (o tom jsme se nebavili).
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Filip Jirsák 14. 04. 2018, 22:53:37
Pokazdy, kdyz ti vyvratim tvoje tvrzeni, tak prijdes s necim jinym.
Tak ta moje pravdivá tvrzení nevyvracejte a já vám pak nebudu muset pomocí dalších tvrzení dokazovat, že jsou pravdivá.

jestli JVM potrebuje singatures (o tom jsme se nebavili).
Ne, o tom jsme se vůbec nebavili, akorát tím celá debata začala, když jsem vám vysvětloval, že kolekce nemůže použít vlastnosti žádného jiného typu, protože za běhu v JVM je v kolekci jenom typ Object.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Karel Rank 14. 04. 2018, 23:09:56
Pokazdy, kdyz ti vyvratim tvoje tvrzeni, tak prijdes s necim jinym.
Tak ta moje pravdivá tvrzení nevyvracejte a já vám pak nebudu muset pomocí dalších tvrzení dokazovat, že jsou pravdivá.

jestli JVM potrebuje singatures (o tom jsme se nebavili).
Ne, o tom jsme se vůbec nebavili, akorát tím celá debata začala, když jsem vám vysvětloval, že kolekce nemůže použít vlastnosti žádného jiného typu, protože za běhu v JVM je v kolekci jenom typ Object.

Napsal si na zacatku bs, pak ses ho snazil podporit polovicni pravdou a nakonec si hrajes na to, jak mentorujes. Pridavas irelevantni veci a zamotavas se do toho.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Karel Rank 15. 04. 2018, 03:32:53
Pokazdy, kdyz ti vyvratim tvoje tvrzeni, tak prijdes s necim jinym.
Tak ta moje pravdivá tvrzení nevyvracejte a já vám pak nebudu muset pomocí dalších tvrzení dokazovat, že jsou pravdivá.

jestli JVM potrebuje singatures (o tom jsme se nebavili).
Ne, o tom jsme se vůbec nebavili, akorát tím celá debata začala, když jsem vám vysvětloval, že kolekce nemůže použít vlastnosti žádného jiného typu, protože za běhu v JVM je v kolekci jenom typ Object.

Napsal si na zacatku bs, pak ses ho snazil podporit polovicni pravdou a nakonec si hrajes na to, jak mentorujes. Pridavas irelevantni veci a zamotavas se do toho.

Btw, your code suck on github. Machrujes, jak umis bytecoe, ale neohlidas si zakladni veci v kontraktu v tridas co publikujes. What a kind-of-cunt. l33t c0d3r v OKsystems (docela dost lidi te tam nema rado kvuli ego).

Takovy egoisticky idoty jako ty potrebujeme. Jak resis tydle veci s new joiner in the team? A kdyz to fresh from colleage?
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: kvr kvr 15. 04. 2018, 04:14:05
Například v tomhle kódu vám to druhé vlákno může vypsat 0, 1 nebo i hodnotu, kterou měla ta položka ještě dříve.
Kód: [Vybrat]
Item item = synchronizedMap.get("item1");
item.setValue(0);
new Thread(() -> item.setValue(1)).start();
new Thread(() -> System.out.println(item.getValue())).start();

Nemůže. Může vypsat 0, 1 nebo hodnotu, kterou bude mít položka později. Nemůže vypsat dřívější, bo Thread.start() invokuje memory barrier (z hlediska JVM zajišťuje happened-before), podobně jako Thread.join().
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Karel Rank 15. 04. 2018, 04:39:58
Například v tomhle kódu vám to druhé vlákno může vypsat 0, 1 nebo i hodnotu, kterou měla ta položka ještě dříve.
Kód: [Vybrat]
Item item = synchronizedMap.get("item1");
item.setValue(0);
new Thread(() -> item.setValue(1)).start();
new Thread(() -> System.out.println(item.getValue())).start();

Nemůže. Může vypsat 0, 1 nebo hodnotu, kterou bude mít položka později. Nemůže vypsat dřívější, bo Thread.start() invokuje memory barrier (z hlediska JVM zajišťuje happened-before), podobně jako Thread.join().

Bam!
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Lol Phirae 15. 04. 2018, 05:53:44
(https://image.ibb.co/bysM2S/pissing_contest.jpg)
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Filip Jirsák 15. 04. 2018, 08:55:40
Napsal si na zacatku bs, pak ses ho snazil podporit polovicni pravdou a nakonec si hrajes na to, jak mentorujes. Pridavas irelevantni veci a zamotavas se do toho.
Na začátku jste vy napsal (https://forum.root.cz/index.php?topic=18205.msg260699#msg260699) nesmysl, že když se modifikují prvky kolekce, musí být synchronizovány přes stejný monitor. To jsem vám vyvrátil, načež jste začal tvrdit, že kolekce interně pracují i s jinými typy, než je typ Object. A tak to pokračuje dál a dál, vždycky vám vyvrátím jeden nesmysl a vy přijdete s jiným.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Filip Jirsák 15. 04. 2018, 09:03:09
Například v tomhle kódu vám to druhé vlákno může vypsat 0, 1 nebo i hodnotu, kterou měla ta položka ještě dříve.
Kód: [Vybrat]
Item item = synchronizedMap.get("item1");
item.setValue(0);
new Thread(() -> item.setValue(1)).start();
new Thread(() -> System.out.println(item.getValue())).start();

Nemůže. Může vypsat 0, 1 nebo hodnotu, kterou bude mít položka později. Nemůže vypsat dřívější, bo Thread.start() invokuje memory barrier (z hlediska JVM zajišťuje happened-before), podobně jako Thread.join().
Já jsem si říkal, jestli ten kód můžu takhle zjednodušit a bude každému jasné, že jde jenom o ten princip, že vytažení prvku ze synchronizované kolekce neříká vůbec nic o synchronizaci toho prvku. Ale máte pravdu, měl jsem buď ten text upravit, aby přesně popisoval ten kód, a nebo nechat ta vlákna nastartovaná dříve, aby tam opravdu nebyla žádná paměťová bariéra.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondrej Nemecek 15. 04. 2018, 11:14:05
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 (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ů.

Na jiny masine to muze vypadat jinak. Proto je to race condition. A je jedno jestli to je absenci synchronizace nebo spatny synchronizaci.

Rozdíl je v tom, že v druhém případě je jasné, že si od začátku uvědomuju nutnost synchronizace akorát jsem ji (pod dojmem toho nepravého singelotnu) špatně provedl. A reaguju tím na vaše doporučení, abych to udělal thread-safe, což už je v diskuzi dávno zmíněno - poprvé v mém původním dotazu a posléze potvrzeno ostatními. Mimo jiné právě proto jsem nerozuměl, co svým příspěvkem vlastně chcete říct, přišlo mi to jako takový výstřel do tmy  :)
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Karel Rank 15. 04. 2018, 21:11:43
Napsal si na zacatku bs, pak ses ho snazil podporit polovicni pravdou a nakonec si hrajes na to, jak mentorujes. Pridavas irelevantni veci a zamotavas se do toho.
Na začátku jste vy napsal (https://forum.root.cz/index.php?topic=18205.msg260699#msg260699) nesmysl, že když se modifikují prvky kolekce, musí být synchronizovány přes stejný monitor. To jsem vám vyvrátil, načež jste začal tvrdit, že kolekce interně pracují i s jinými typy, než je typ Object. A tak to pokračuje dál a dál, vždycky vám vyvrátím jeden nesmysl a vy přijdete s jiným.

Ne nevyvratil. Pridal si do toho deadlock. O kterym jsme se opet nebavili. Je to jen show-off od tebe.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Karel Rank 15. 04. 2018, 21:16:41
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 (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ů.

Na jiny masine to muze vypadat jinak. Proto je to race condition. A je jedno jestli to je absenci synchronizace nebo spatny synchronizaci.

Rozdíl je v tom, že v druhém případě je jasné, že si od začátku uvědomuju nutnost synchronizace akorát jsem ji (pod dojmem toho nepravého singelotnu) špatně provedl. A reaguju tím na vaše doporučení, abych to udělal thread-safe, což už je v diskuzi dávno zmíněno - poprvé v mém původním dotazu a posléze potvrzeno ostatními. Mimo jiné právě proto jsem nerozuměl, co svým příspěvkem vlastně chcete říct, přišlo mi to jako takový výstřel do tmy  :)

Precetl jsem si jen prvni stranku. A reagoval. Dal jsem to i do statement.

Tu knizku ti muzu poslat. Bude to i s postovnym asi $28. Dej vedet.
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Filip Jirsák 15. 04. 2018, 23:12:30
Ne nevyvratil. Pridal si do toho deadlock. O kterym jsme se opet nebavili. Je to jen show-off od tebe.

Chcete tvrdit, že když máte mapu definovanou následujícím způsobem:

Kód: [Vybrat]
Map<String, AtomicLong> counter = new HashMap<>()a chcete tu mapu i její prvky modifikovat z více vláken, musíte modifikaci prvků synchronizovat přes stejný monitor, jako přístup k mapě? Podle vás je následující kód špatně?

Kód: [Vybrat]
public long increment(String name) {
  AtomicLong namedCounter;
  try {
    lock.readLock().lock();
    namedCounter = counter.get(name);
  } finally {
    lock.readLock().unlock();
  }
  return namedCounter.incrementAndGet();
}

Jak by ten kód byl podle vás správně, aby se increment() dalo volat bezpečně z více vláken?
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: kvr kvr 15. 04. 2018, 23:50:28
Podle vás je následující kód špatně?

Ano, je špatně. Správně má být:

Kód: [Vybrat]
public long increment(String name) {
  AtomicLong namedCounter;
  lock.readLock().lock();
  try {
    namedCounter = counter.get(name);
  } finally {
    lock.readLock().unlock();
  }
  return namedCounter.incrementAndGet();
}
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Karel Rank 16. 04. 2018, 00:34:59
Podle vás je následující kód špatně?

Ano, je špatně. Správně má být:

Kód: [Vybrat]
public long increment(String name) {
  AtomicLong namedCounter;
  lock.readLock().lock();
  try {
    namedCounter = counter.get(name);
  } finally {
    lock.readLock().unlock();
  }
  return namedCounter.incrementAndGet();
}

A hodi ti to NPE kdyz neexistuje name[\tt] v mape.

Snazis se furt dokazat, ze mas polovicni znalosti JLS, JMM a pouzivas je jak se ti to hodi?
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Filip Jirsák 16. 04. 2018, 07:31:16
Fajn. Volání incrementAndGet() ten element kolekce modifikuje. Volání incrementAndGet() není synchronizováno přes stejný monitor jako kolekce ani jako jiné elementy kolekce. Takže jste sám uvedl protipříklad vyvracející pravdivost vašeho tvrzení „Jestli se modifikujou elementy kolekce, tak musi byt samozrejme synchronizovany pres stejny monitor.“
Název: Re:Java: Mám neprázdný Set, ale nemůžu z něj dostat položky
Přispěvatel: Ondrej Nemecek 16. 04. 2018, 13:57:28
Precetl jsem si jen prvni stranku. A reagoval. Dal jsem to i do statement.
Samozřejmě vím, že jste to uvedl. A já se zeptal, co tím příspěvkem vlastně myslíte, když to je už vyřešené.

Uzavřeme to: Synchronizoval jsem přes špatný zámek, protože jsem mylně předpokládal tvrdý singleton. Tím vznikla race condition v kokurenčním multi-threaded prostředí a ta mě vypekla. Po změně zámku to funguje. V diskuzi dále zazněly další doporučení, jak aplikaci pro dané použití lépe strukturovat a byla doporučena literatura. To je ta část diskuze, která pro mě měla smysl.
Tu knizku ti muzu poslat. Bude to i s postovnym asi $28. Dej vedet.
Děkuju, vystačím s tím co mám.