CodeGym /Java blog /Véletlen /Többszálú Java nyelven
John Squirrels
Szint
San Francisco

Többszálú Java nyelven

Megjelent a csoportban
Szia! Először is gratulálok: elérted a Java Multithreading témáját! Ez komoly eredmény – hosszú utat tett meg. De készülj fel: ez az egyik legnehezebb téma a tanfolyamon. És itt nem arról van szó, hogy bonyolult osztályokat vagy sok módszert használunk: valójában húsznál kevesebbet fogunk használni. Sokkal inkább arról van szó, hogy kicsit megváltoztatnod kell a gondolkodásodat. Korábban a programjait szekvenciálisan hajtották végre. Egyes kódsorok jöttek mások után, néhány metódus mások után, és alapvetően minden világos volt. Először kiszámoltunk valamit, majd megjelenítettük az eredményt a konzolon, majd a program véget ért. A többszálú használat megértéséhez jobb, ha párhuzamosságban gondolkodunk. Kezdjük valami egészen egyszerűvel: ) Képzelje el, hogy a családja egyik házból a másikba költözik. Az összes könyv összegyűjtése fontos része lesz a lépésnek. Rengeteg könyvet halmozott fel, és dobozokba kell tennie őket. Jelenleg te vagy az egyetlen elérhető. Anya ételt készít, a bátyja ruhákat csomagol, a nővére meg elment a boltba. Egyedül valahogy kibírod. Előbb-utóbb Ön is megoldja a feladatot, de ez sok időt vesz igénybe. Viszont a nővéred 20 perc múlva visszajön a boltból, és nincs más dolga. Szóval csatlakozhat hozzád. A feladat nem változott: tedd a könyveket dobozokba. De kétszer olyan gyorsan hajtják végre. Miért? Mert párhuzamosan folyik a munka. Két különböző „szál” (te és a nővére) ugyanazt a feladatot végzi egyszerre. És ha semmi sem változik, akkor óriási időkülönbség lesz ahhoz képest, amikor mindent egyedül csinál. Ha a testvér hamarosan befejezi a munkáját, tud segíteni, és a dolgok még gyorsabban mennek.

Többszálú megoldással megoldott problémák

A többszálas megoldást valójában két fontos cél elérése érdekében találták ki:
  1. Csinálj több dolgot egyszerre.

    A fenti példában a különböző szálak (családtagok) több műveletet hajtottak végre párhuzamosan: mosogattak, elmentek a boltba, és összepakoltak.

    A programozáshoz közelebbről is tudunk példát mondani. Tegyük fel, hogy van egy felhasználói felülettel rendelkező programja. Amikor a programban a „Tovább” gombra kattint, néhány számításnak meg kell történnie, és a felhasználónak a következő képernyőt kell látnia. Ha ezeket a műveleteket egymás után hajtják végre, akkor a program lefagy, miután a felhasználó a „Folytatás” gombra kattint. A felhasználó addig fogja látni a „Folytatás” gomb képernyőjét, amíg a program elvégzi az összes belső számítást és el nem éri azt a részt, ahol a felhasználói felület frissül.

    Nos, azt hiszem, várunk egy pár percet!

    Többszálú Java nyelv: mi ez, előnyei és gyakori buktatói - 3

    Vagy átdolgozhatjuk a programunkat, vagy ahogy a programozók mondják, „párhuzamba állíthatjuk”. Végezzük el a számításainkat az egyik szálon, és rajzoljuk meg a felhasználói felületet egy másik szálon. A legtöbb számítógép elegendő erőforrással rendelkezik ehhez. Ha ezt az utat választjuk, akkor a program nem fagy le, és a felhasználó gördülékenyen mozog a képernyők között anélkül, hogy aggódnia kellene a benti események miatt. Egyik nem zavarja a másikat :)

  2. Gyorsabban végezzen számításokat.

    Itt minden sokkal egyszerűbb. Ha a processzorunk több maggal rendelkezik, és a legtöbb processzor ma is rendelkezik, akkor több mag képes párhuzamosan kezelni a feladatlistánkat. Nyilvánvalóan, ha 1000 feladatot kell végrehajtanunk, és mindegyik egy másodpercet vesz igénybe, akkor egy mag 1000 másodperc alatt, két mag 500 másodperc alatt, három valamivel több, mint 333 másodperc alatt fejezheti be a listát, stb.

De ahogy ebben a leckében már olvashatta, a mai rendszerek nagyon okosak, és akár egyetlen számítási magon is képesek párhuzamosságot, vagy inkább pszeudo-párhuzamot elérni, ahol a feladatokat felváltva hajtják végre. Térjünk át az általánosságra a konkrétumokra, és ismerjük meg a Java többszálú könyvtár legfontosabb osztályát – java.lang.Thread. Szigorúan véve a Java szálakat a Thread osztály példányai képviselik . Ez azt jelenti, hogy 10 szál létrehozásához és futtatásához ennek az osztálynak 10 példányára van szüksége. Írjuk a legegyszerűbb példát:

public class MyFirstThread extends Thread {

   @Override
   public void run() {
       System.out.println("I'm Thread! My name is " + getName());
   }
}
Szálak létrehozásához és futtatásához létre kell hoznunk egy osztályt, amely örökli a java.lang fájlt . Szálosztályt , és felülírja a run() metódust. Ez utóbbi követelmény nagyon fontos. A run() metódusban határozzuk meg a szálunk végrehajtásának logikáját. Most, ha létrehozzuk és futtatjuk a MyFirstThread példányát , a run() metódus egy sort jelenít meg egy névvel: a getName() metódus megjeleníti a szál „rendszer” nevét, amely automatikusan hozzá van rendelve. De miért beszélünk próbaképpen? Hozzunk létre egyet, és megtudjuk!

public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {

           MyFirstThread thread = new MyFirstThread();
           thread.start();
       }
   }
}
Konzol kimenet: Thread vagyok! A nevem Thread-2 Thread vagyok! A nevem Thread-1 Thread vagyok! A nevem Thread-0 Thread vagyok! A nevem Thread-3 Thread vagyok! A nevem Thread-6 Thread vagyok! A nevem Thread-7 Thread vagyok! A nevem Thread-4 Thread vagyok! A nevem Thread-5 Thread vagyok! A nevem Thread-9 Thread vagyok! A nevem Thread-8 Hozzunk létre 10 szálat ( MyFirstThread objektumokat, amelyek öröklik a Thread -t ), és indítsuk el őket a start() metódus meghívásával minden objektumon. A start() metódus meghívása után a run() metódusban szereplő logika végrehajtásra kerül. Megjegyzés: a szálnevek nem sorrendben vannak. Furcsa, hogy nem egymás után voltak:, Thread-1 , Thread-2 , és így tovább? Amint megtörténik, ez egy példa arra az időszakra, amikor a „szekvenciális” gondolkodás nem fér bele. A probléma az, hogy csak 10 szál létrehozásához és futtatásához adtunk parancsokat. A szálütemező, egy speciális operációs rendszer-mechanizmus, határozza meg a végrehajtási sorrendjüket. Pontos tervezése és döntéshozatali stratégiája olyan mély viták témája, amelyekbe most nem merülünk bele. A legfontosabb, hogy ne feledje, hogy a programozó nem tudja szabályozni a szálak végrehajtási sorrendjét. A helyzet súlyosságának megértéséhez próbálja meg még néhányszor futtatni a main() metódust a fenti példában. Konzol kimenet második futtatáskor: Thread vagyok! A nevem Thread-0 Thread vagyok! A nevem Thread-4 Thread vagyok! A nevem Thread-3 Thread vagyok! A nevem Thread-2 Thread vagyok! A nevem Thread-1 Thread vagyok! A nevem Thread-5 Thread vagyok! A nevem Thread-6 Thread vagyok! A nevem Thread-8 Thread vagyok! A nevem Thread-9 Thread vagyok! A nevem Thread-7 konzol kimenete a harmadik futtatásból: Thread vagyok! A nevem Thread-0 Thread vagyok! A nevem Thread-3 Thread vagyok! A nevem Thread-1 Thread vagyok! A nevem Thread-2 Thread vagyok! A nevem Thread-6 Thread vagyok! A nevem Thread-4 Thread vagyok! A nevem Thread-9 Thread vagyok! A nevem Thread-5 Thread vagyok! A nevem Thread-7 Thread vagyok! A nevem Thread-8

Többszálú feldolgozás okozta problémák

A könyvekkel kapcsolatos példánkban láthatta, hogy a többszálú megoldás nagyon fontos feladatokat old meg, és gyorsabbá teheti programjainkat. Sokszor gyorsabban. De a többszálú feldolgozást nehéz témának tartják. Valójában, ha nem megfelelően használják, problémákat okoz, ahelyett, hogy megoldaná azokat. Amikor azt mondom, hogy „problémákat okoz”, nem valamilyen elvont értelemben értem. A többszálú használat két konkrét problémát okozhat: holtpont és versenyfeltételek. A holtpont olyan helyzet, amikor több szál vár egymás által birtokolt erőforrásokra, és egyikük sem futhat tovább. Erről bővebben a következő leckéken fogunk beszélni. Egyelőre elegendő a következő példa: Többszálú Java nyelv: mi ez, előnyei és gyakori buktatói - 4Képzelje el, hogy az 1. szál kölcsönhatásba lép néhány objektummal, és a 2. szál kölcsönhatásba lép a 2. objektummal. Továbbá a program úgy van megírva, hogy:
  1. Az 1-es szál leállítja az 1-es objektummal való interakciót, és átvált a 2-es objektumra, amint a 2-es szál abbahagyja az Object-2-vel való interakciót, és átvált az Object-1-re.
  2. A 2. szál leállítja a 2. objektum interakcióját, és átvált az 1. objektumra, amint az 1. szál abbahagyja az 1. objektum interakcióját, és átvált az Object-2-re.
A multithreading mély ismerete nélkül is könnyen beláthatja, hogy semmi sem fog történni. A szálak soha nem cserélnek helyet, és örökké egymásra várnak. A hiba nyilvánvalónak tűnik, de a valóságban nem az. Ezt könnyen megteheti egy programban. A következő leckékben megvizsgálunk példákat a holtpontot okozó kódokra. Mellesleg, a Quorának van egy nagyszerű valós példája , amely megmagyarázza, mi a holtpontvan. „India egyes államaiban csak akkor adnak el Önnek mezőgazdasági földet, ha bejegyzett gazdálkodó. Mindazonáltal nem regisztrálnak gazdálkodóként, ha nem rendelkezik mezőgazdasági földterülettel”. Nagy! Mit is mondhatnánk?! :) Most beszéljünk a versenykörülményekről. A versenyfeltétel egy többszálú rendszer vagy alkalmazás tervezési hibája, ahol a rendszer vagy alkalmazás működése attól függ, hogy a kód egyes részei milyen sorrendben kerülnek végrehajtásra. Emlékezzen a példánkra, ahol szálakat indítottunk:

public class MyFirstThread extends Thread {

   @Override
   public void run() {
       System.out.println("Thread executed: " + getName());
   }
}

public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {

           MyFirstThread thread = new MyFirstThread();
           thread.start();
       }
   }
}
Most képzeljük el, hogy a program egy ételt főző robot működtetéséért felelős! A 0-ás szál kiveszi a tojásokat a hűtőből. Az 1-es szál bekapcsolja a tűzhelyet. A 2. szál kap egy serpenyőt, és felteszi a tűzhelyre. A 3. szál meggyújtja a kályhát. A 4-es szál olajat önt a serpenyőbe. Az 5-ös szál feltöri a tojásokat és beleönti a serpenyőbe. A 6-os szál a szemetesbe dobja a tojáshéjakat. A 7-es szál eltávolítja a főtt tojást az égőből. A 8-as szál tányérra teszi a főtt tojást. A 9-es szál mosogat. Tekintse meg programunk eredményét: Szál végrehajtva: Thread-0 Szál végrehajtva: Thread-2 Szál végrehajtva Thread-1 Szál végrehajtva: Thread-4 Szál végrehajtva: Thread-9 Szál végrehajtva: Thread-5 Szál végrehajtva: Thread-8 Thread végrehajtva: Thread-7 Szál végrehajtva: Thread-3 Ez egy komédia rutin? :) És mindez azért, mert a programunk munkája a szálak végrehajtási sorrendjétől függ. A szükséges sorrend legkisebb megsértése esetén konyhánk pokollá változik, és egy őrült robot mindent elpusztít maga körül. Ez a többszálú programozásban is gyakori probléma. Többször hallani fogsz róla. A lecke befejezéseként szeretnék egy könyvet ajánlani a többszálú feldolgozásról. Többszálú Java nyelv: mi ez, előnyei és gyakori buktatói - 6A „Java Concurrency in Practice” 2006-ban íródott, de nem vesztette el jelentőségét. A többszálú Java programozásnak szentelték – az alapoktól a leggyakoribb hibákig és antimintákig. Ha egy nap úgy döntesz, hogy többszálú guru leszel, ezt a könyvet kötelező elolvasnod. Találkozunk a következő leckéken! :)
Hozzászólások
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION