4 Metoder för att skriva flera trådar i Java
Multi-threading är ett sätt att skriva kod för att utföra uppgifter parallellt. Java har haft utmärkt stöd för att skriva multi-threaded kod sedan de första dagarna av Java 1.0. Nya förbättringar till Java har ökat sätten på vilken kod kan struktureras för att införliva flera trådar i Java-program.
I den här artikeln jämför vi några av dessa alternativ så att du bättre kan bedöma vilket alternativ som ska användas för din nästa Java Projec Love GitHub? 4 Anledningar till varför du borde vara värd för din kod på BitBucket Love GitHub? 4 skäl till att du borde vara värd för din kod på BitBucket Du måste tänka på var du tänker lagra din kod. Det är troligt att du har hört talas om GitHub. Det är inte förvånande. GitHub används av individer och företag att vara värdkod, samarbetar om dokumentation ... Läs mer t.
Metod 1: Utvidga gängklassen
Java tillhandahåller a Tråd klass som kan förlängas för att genomföra springa() metod. Denna run () -metod är där du implementerar din uppgift. När du vill sparka upp uppgiften i sin egen tråd kan du skapa en förekomst av denna klass och anropa sin Start() metod. Detta startar tråden exekvering och körs till slutförandet (eller avslutas i ett undantag).
Här är en enkel trådklass som bara sover för ett visst intervall som ett sätt att simulera en långvarig operation.
offentlig klass MyThread utökar tråd privat int sleepFor; allmän MyThread (int sleepFor) this.sleepFor = sleepFor; @Override public void run () System.out.printf ("[% s] tråd startar \ n", Thread.currentThread (). ToString ()); försök Thread.sleep (this.sleepFor); catch (InterruptedException ex) System.out.printf ("[% s] trådändring \ n", Thread.currentThread (). toString ());
Skapa en förekomst av denna trådklass genom att ge det antalet millisekunder att sova.
MyThread worker = new MyThread (sleepFor);
Kick av utförandet av den här arbetartråden genom att aktivera startmetoden (). Denna metod returnerar kontrollen direkt till den som ringer, utan att vänta på att tråden ska avslutas.
worker.start (); System.out.printf ("[% s] huvudgänga \ n", Thread.currentThread (). ToString ());
Och här är utmatningen från att köra den här koden. Det indikerar att huvudtrådsdiagnosen skrivs ut innan arbetstråden körs.
[Tråd [huvud, 5, huvud]] huvudgänga [tråd [tråd-0,5, huvud]] tråd start [tråd [tråd-0,5, huvud]] trådändning
Eftersom det inte finns några uttalanden efter att arbetstråden har startats väntar huvudgängan på att arbetstråden ska slutföras innan programmet avslutas. Detta gör det möjligt för arbetstråden att slutföra sin uppgift.
Metod 2: Använda en trådinstans med en runnable
Java ger också ett gränssnitt som heter Runnable som kan genomföras av en arbetarklass för att utföra uppgiften i sin springa() metod. Detta är ett alternativt sätt att skapa en arbetarklass i motsats till att utöka Tråd klass (beskrivet ovan).
Här är implementeringen av arbetarklassen som nu implementerar Runnable istället för att förlänga Thread.
offentliga klass MyThread2 implementerar Runnable // samma som ovan
Fördelen med att implementera Runnable-gränssnittet istället för att förlänga Thread-klassen är att arbetarklassen nu kan utöka en domänspecifik klass inom en klasshierarki.
Vad betyder det här?
Låt oss säga, till exempel, har du en Frukt klass som implementerar vissa generiska egenskaper hos frukter. Nu vill du genomföra en Papaya klass som specialiserar vissa frukt egenskaper. Du kan göra det genom att ha Papaya klassen förlänger Frukt klass.
offentlig klass Frukt // fruktspecifikationer här offentlig klass Papaya förlänger frukt // override behavior specific to papaya here
Antag nu att du har en tidskrävande uppgift som Papaya behöver stödja, vilket kan utföras i en separat tråd. Detta fall kan hanteras genom att Papaya-klassen implementerar Runnable och tillhandahålla run () -metoden där den här uppgiften utförs.
offentlig klass Papaya förlänger fruktredskap Runnable // överträffande beteende specifikt för papaya här @Override public void run () // tidskrävande uppgift här.
För att sparka av arbetstråden skapar du en förekomst av arbetarklassen och överlämnar den till en trådinstans vid skapandet. När startmetoden start () används, utförs uppgiften i en separat tråd.
Papaya Papaya = Ny Papaya (); // Ange egenskaper och använd papaya metoder här. Tråd = Ny tråd (papaya); thread.start ();
Och det är en kort sammanfattning av hur man använder en Runnable för att genomföra en uppgift som utförs inom en tråd.
Metod 3: Utför en Runnable med ExecutorService
Från och med version 1.5 tillhandahåller Java en ExecutorService som ett nytt paradigm för att skapa och hantera trådar inom ett program. Det generaliserar begreppet trådutförande genom att abstrahera skapandet av trådar.
Detta beror på att du kan köra dina uppgifter inom en trådsträng lika enkelt som att använda en separat tråd för varje uppgift. Detta låter ditt program spåra och hantera hur många trådar som används för arbetstagarens uppgifter.
Antag att du har 100 anställda uppgifter som väntar på att utföras. Om du startar en tråd per arbetare (enligt ovan), skulle du ha 100 trådar inom ditt program vilket kan leda till flaskhalsar någon annanstans inom programmet. Istället, om du använder en trådpool med, säger 10 trådar som är fördelade, kommer dina 100 uppgifter att utföras av dessa trådar en efter en, så ditt program är inte svalt för resurser. Dessutom kan dessa trådspårtrådar konfigureras så att de hänger runt för att utföra ytterligare uppgifter för dig.
En ExecutorService accepterar a Runnable uppgift (förklarad ovan) och kör uppgiften vid en lämplig tidpunkt. De lämna() metod som accepterar Runnable-uppgiften returnerar en instans av en klass som heter Framtida, som låter uppringaren spåra status för uppgiften. I synnerhet skaffa sig() Metoden låter uppringaren vänta på att uppgiften ska slutföras (och tillhandahåller returkoden, om någon finns).
I exemplet nedan skapar vi en ExecutorService med den statiska metoden newSingleThreadExecutor (), som som namnet indikerar skapar en enda tråd för att utföra uppgifter. Om flera uppgifter lämnas in medan en uppgift körs köper ExecutorService dessa uppgifter för senare utförande.
Det genomförbara genomförandet vi använder här är detsamma som beskrivits ovan.
ExecutorService esvc = Executors.newSingleThreadExecutor (); Runnable worker = new MyThread2 (sleepFor); Framtida> future = esvc.submit (arbetare); System.out.printf ("[% s] huvudgänga \ n", Thread.currentThread (). ToString ()); future.get (); esvc.shutdown ();
Observera att en ExecutorService måste stängas ordentligt när den inte längre behövs för ytterligare uppgiftsinsändningar.
Metod 4: En Callable Används Med ExecutorService
Från och med version 1.5 introducerade Java ett nytt gränssnitt som heter inlösbara. Det liknar det äldre Runnable gränssnittet med skillnaden att exekveringsmetoden (kallad ring upp() istället för springa()) kan returnera ett värde. Dessutom kan det också deklarera att en Undantag kan kastas.
En ExecutorService kan också acceptera uppgifter som implementeras som inlösbara och returnerar a Framtida med det värde som returneras av metoden vid slutförandet.
Här är ett exempel Mango klass som sträcker sig Frukt klass definieras tidigare och implementerar inlösbara gränssnitt. En dyr och tidskrävande uppgift utförs inom ring upp() metod.
public class Mango utökar fruktredskap Callable public Integer call () // dyra beräkning här returnera nytt heltal (0);
Och här är koden för att skicka en instans av klassen till en ExecutorService. Koden nedan väntar också på uppgiften att slutföra och skriva ut sitt returvärde.
ExecutorService esvc = Executors.newSingleThreadExecutor (); MyCallable worker = new MyCallable (sleepFor); Framtida framtid = esvc.submit (worker); System.out.printf ("[% s] huvudgänga \ n", Thread.currentThread (). ToString ()); System.out.println ("Uppgift returnerad:" + future.get ()); esvc.shutdown ();
Vad föredrar du?
I den här artikeln lärde vi oss några metoder för att skriva multi-threaded-kod i Java. Dessa inkluderar:
- Förlängning av Tråd klassen är den mest grundläggande och har varit tillgänglig från Java 1.0.
- Om du har en klass som måste förlänga någon annan klass i en klasshierarki, kan du implementera Runnable gränssnitt.
- En modernare anläggning för att skapa trådar är ExecutorService som kan acceptera en Runnable-instans som en uppgift att köra. Fördelen med den här metoden är att du kan använda en trådpool för att utföra uppdrag. En trådpool hjälper till att spara resurser genom att återanvända trådar.
- Slutligen kan du också skapa en uppgift genom att implementera inlösbara gränssnitt och skicka uppgiften till en ExecutorService.
Vilka av dessa alternativ tror du att du kommer att använda i ditt nästa projekt? Låt oss veta i kommentarerna nedan.
Utforska mer om: Java.