Multithreading és Synchronization
Threading problémák
Probléma 1 - hozzáférés egy forrásból több szálból. A problémát egy ásóval már ismertettük. Bővíthető a lehetőség - van egy tartály vízzel (egy csappal), 25 szomjas bányászok és 5 bögrék egyáltalán. Meg kell tárgyalnunk, különben megölni lehet. És nem csak a körök integritását kell tartanunk - még mindig mindent meg kell szerveznünk, hogy mindenki inni tudjon. Ez részben a második probléma.
A második probléma az interakció szinkronizálása. Valahogy felajánlották nekem, hogy írjak egy egyszerű programot a két ping-pong-pókra. Az egyik azt írja: "Ping", és a második - "Pong". De ezt meg kell tenniük. És most képzeljük el, hogy ugyanazt a feladatot kell elvégeznünk, de 4 szálon - egy párt játsszunk egy párért.
Ie a problémák megfogalmazása nagyon egyszerű. Idő - meg kell szervezni a rendezett és biztonságos hozzáférést a megosztott erőforráshoz. Két - szálakat kell végrehajtani bizonyos sorrendben.
Az ügy a végrehajtás mögött van. És itt sok nehézséggel szembesülünk, amelyekről egy prehannel beszélnek (és tudatosan is). Kezdjük a megosztott erőforrással.
Több szálat tartalmazó megosztott erőforrás
Javaslom, hogy a problémát egyszerű példával szemléltessük. Feladata, hogy 200 szálat futtasson a CounterThread osztályból. Minden téma referenciát kap egyetlen számlálóhoz. A futtatás során a szál ezt a módszert 1000-szer növeli a Counter-módszerrel. A módszer növeli a változó számlálót 1-szel. 200 szálat futtatunk, elvárjuk tőlük, hogy vége legyen (csak 1 másodpercre elaludjon - elég ez). És végül kinyomtatjuk az eredményt. Nézd meg a kódot - véleményem szerint minden átlátható:
A megosztott erőforrásokhoz való hozzáférés a multithreading egyik legnagyobb problémája. Mert nagyon titokban áll. Mindent megtesz, nagyon megbízhatóan, de a teljesítmény csökken. És amint "tudatosan, a termelékenységhez" adsz "lazaságot", feltétlenül olyan helyzetet fogsz előidézni, amely "laza" lesz minden dicsőségében.
A mágikus szó szinkronizálva van
Mit tehetünk annak érdekében, hogy megszabaduljunk a helyzettől, amelyben a mi figyelemre méltó áramlásainkkal csökkentünk. Kezdjük egy kis spekulációval. Amikor eljutunk a boltba, akkor fizetés esetén a pénztárba jutunk. A pénztáros egyszerre csak egy személyt szolgál ki. Mindannyian sorban állunk. Valójában a pénztár kizárólagos erőforrássá válik, amelyet csak egy vevő használhat egyszerre. A multithreadelésben ugyanazt a módszert javasoljuk - bizonyos erőforrásokat úgy definiálhatunk, mintha csak egy szálat tudnánk egyszerre biztosítani. Ezt az erőforrást "monitornak" nevezik. Ez a leggyakoribb objektum, amelyet egy szálnak "rögzítenie" kell. Minden olyan szálat, amely ezt a monitort (objektumot) szeretné elérni, sorakoznak. És ehhez nem kell külön kódot írni - csak próbálja megragadni a monitort. De hogyan kell kijelölni ezt. Értsük meg.
Azt javaslom, hogy futtassuk a példát, de egy további szóval a módszer leírásában a növekedés a szinkronizált szó.
Külön használata szinkronizált csinál lényegében ugyanaz - az első blokkoló / lochit utalt rá zárójelben kifogást majd elkezd kód végrehajtását, amely belülről szinkronizálni. Itt figyelembe kell venni, hogy a blokkolás nem a módszer bemenetén, hanem a szinkronizált mondat bejáratánál fog megjelenni. Ennek köszönhetően több objektumon belüli objektumokat is szinkronizálhat. Például két módszer egy objektumot blokkol, és kettőt blokkol egy másikat. Ezután különböző csoportokból származó módszereket hívhat le egyszerre. Ezt használtam a gyakorlatomban.
Elvben a szinkronizált gondolat kimerült. Most a helyes használata fontos lesz. Mert egyfelől vágyakozhatunk arra, hogy minden módszer szinkronizálódjon. de ez hatással lesz a teljesítményre - szerintem ez nyilvánvaló. Másrészt nehézségek adódhatnak a nem szinkronizált objektumok pontatlan kezelésében. Szóval legyen éber.
Menetbiztos osztályok - menet biztonságos
A getCounter metódus egyszerűen a dokumentációban szálbiztosként deklarálható. És ha a Counter osztályban a setCounter módszer végrehajtására kerül sor, akkor e két módszer szinkronizálása nem lesz semmi értelme.
Nos, itt volt a feladata annak bizonyítása, hogy sok szál megsérti az adatokat. És utána mutasd meg, hogyan lehet ezt megoldani. Van egy érzésem, hogy senki sem olvassa a magyarázó szöveget, csak nézze meg a kódot, és csak következtetéseket von le rajta. Igen, a kód bizonyos mértékig ellentmondásos, de pontosan azt az ötletet mutatja, amit megpróbáltam bemutatni.
A kijelentésem nem kritika, hanem a többszöveges problémák további megvitatása.
Ez néha történik - nem értettem az okokat.
A Thread.sleep () hívása leállítja az aktuális szálat. Ie azok a 200, akik futnak, őszintén dolgoztak. És a fő módban lévő cérna várakozik.
Kedves Admin, ha jól értem, hogy van egy áramlás a módszer fő, amely (a stream) fut a kód (ciklus), viszont fut 200 szállal, hogy dolgozzanak ki; míg szünetelteti az áramlás a módszer fő, így várta a bányászat a 200-flow maga előtt (fő módszer) befejezi a műveletet.
Vagy a fő módszer menetét elindítjuk, ezzel párhuzamosan a 200-at elindítjuk; A Thread.sleep (1000) lehetővé teszi számukra a munkát, akkor a fő módszer szál folytatódik, az üzenetet a konzolra dobja, majd bezárja.
Sajnálom a kérdést, hogy a kezdeti Java tanfolyamon mindannyian "rágtad"?
Igen, a fő módszer külön szálon történik. Igen, más szálakat indít el, és maga elalszik, hogy bizonyítsa, hogy a többi szál befejeződött.
Az áramlások elvben "azonosak". És a fő szál és az összes szál amit indított.
Igen, az első évben mindannyian rágjuk és sok példát teszünk.
Ilyen feladat: vannak többfunkciós készülékek, egyszerre nyomtathat vagy szkennelhet. Két nyomtató és két szkenner van. Írja be a programot úgy, hogy egy időben az MFP csak egy nyomtató és egy lapolvasó számára álljon rendelkezésre, de ne egyszerre két nyomtatót / szkennert. Ie egyszerre egy oldal nyomtatható és beolvasható egyidejűleg, de két oldal egyidejűleg nem nyomtathat / szkennelhet. A nyomtató / lapolvasó működése a konzolra kerül: "print ..", "scan ..". Valahogy így, görbe módon írt, aki megértette - magyarázza részletesebben.
Az első példa nélkül működik szinkronban, ha a fő szál megvárja befejezését fő húr előtte alkalmazás által generált változó számláló értéke kiadási meghívásával csatlakozik () a keletkező áramlás a hurokban fő. Furcsa módon működik nem csak az int típus, hanem a hosszú számláló változóval.