
Mark Lucas
0
3456
376
Multi-threading er en metode til at skrive kode til parallelt at udføre opgaver. Java har haft fremragende støtte til at skrive multi-threaded kode siden de tidlige dage af Java 1.0. De nylige forbedringer af Java har øget måderne, hvorpå kode kan struktureres til at inkorporere multi-threading i Java-programmer.
I denne artikel sammenligner vi et par af disse indstillinger, så du bedre kan bedømme, hvilken mulighed du skal bruge til din næste Java-projekt, Love GitHub? 4 grunde til, at du skal være vært for din kode på BitBucket Love GitHub? 4 grunde til, at du skal være vært for din kode på BitBucket. Du skal overveje, hvor du har til hensigt at gemme din kode. Det er sandsynligt, at du har hørt om GitHub. Det er ikke overraskende. GitHub bruges af enkeltpersoner og virksomheder til at være værtskode, samarbejde om dokumentation… t.
Metode 1: Udvidelse af trådklassen
Java giver en Tråd klasse, der kan udvides til at implementere løb() metode. Denne run () -metode er det sted, hvor du implementerer din opgave. Når du vil sparke opgaven i sin egen tråd, kan du oprette en forekomst af denne klasse og påkalde dens Start() metode. Dette starter udførelsen af tråd og løber til færdiggørelse (eller afsluttes med undtagelse).
Her er en simpel trådklasse, der bare sover i et specificeret interval som en måde at simulere en langvarig operation.
offentlig klasse MyThread udvider tråd privat int sleepFor; offentlig MyThread (int sleepFor) this.sleepFor = sleepFor; @Override offentligt ugyldigt kørsel () System.out.printf ("[% s] tråd starter \ n", Thread.currentThread (). ToString ()); prøv Thread.sleep (this.sleepFor); fang (InterruptException ex) System.out.printf ("[% s] tråd slutter \ n", Thread.currentThread (). toString ());
Opret et eksempel på denne trådklasse ved at give det antallet af millisekunder at sove.
MyThread-arbejder = ny MyThread (sleepFor);
Start udførelsen af denne arbejdertråd ved at påberåbe sig dens start () -metode. Denne metode returnerer kontrol straks til den, der ringer, uden at vente på, at tråden afsluttes.
worker.start (); System.out.printf ("[% s] hovedtråd \ n", Thread.currentThread (). ToString ());
Og her er output fra kørsel af denne kode. Det angiver, at diagnosen af hovedtråden udskrives, før arbejdertråden udføres.
[Tråd [hoved, 5, hoved]] hovedtråd [Tråd [Tråd-0,5, hoved]] tråd start [Tråd [Tråd-0,5, hoved]] tråd slutt
Da der ikke er flere udsagn efter start af arbejdertråden, venter hovedtråden på, at arbejdertråden afsluttes, før programmet afsluttes. Dette gør det muligt for arbejdertråden at udføre sin opgave.
Metode 2: Brug af en trådforekomst med en kørbar
Java leverer også en interface, der kaldes Runnable som kan implementeres af en arbejderklasse for at udføre opgaven i dens løb() metode. Dette er en alternativ måde at skabe en arbejderklasse i modsætning til at udvide Tråd klasse (beskrevet ovenfor).
Her er implementeringen af arbejderklassen, som nu implementerer Kørbar i stedet for at udvide tråden.
offentlig klasse MyThread2 implementerer Kørbar // samme som ovenfor
Fordelen ved at implementere det Runnable-interface i stedet for at udvide tråden-klassen er, at arbejderklassen nu kan udvide en domænespecifik klasse inden for et klassehierarki.
Hvad betyder det?
Lad os f.eks. Sige, at du har en Frugt klasse, der implementerer visse generiske egenskaber ved frugter. Nu vil du implementere en papaya klasse, der specialiserer visse frugtegenskaber. Du kan gøre det ved at have papaya klasse udvide Frugt klasse.
offentlig klasse frugt // frugtspecifikationer her offentlig klasse papaya udvider frugt // tilsidesætter adfærd, der er specifik for papaya her
Antag nu, at du har en tidskrævende opgave, som Papaya har brug for at støtte, som kan udføres i en separat tråd. Denne sag kan håndteres ved at have Papaya-klassen implementeret Runnable og give køremetoden (), hvor denne opgave udføres.
offentlig klasse Papaya udvider Frugtimplementeringer Kan køres // tilsidesætte opførsel, der er specifik for papaya her @Override public void run () // tidskrævende opgave her.
For at sparke medarbejdertråden opretter du en forekomst af arbejderklassen og overleverer den til en trådforekomst ved oprettelsen. Når start () -metoden for tråden aktiveres, udføres opgaven i en separat tråd.
Papaya papaya = ny Papaya (); // angiv egenskaber og påkald papaya-metoder her. Trådtråd = ny tråd (papaya); thread.start ();
Og det er en kort oversigt over, hvordan man bruger en Runnable til at implementere en opgave, der udføres inden for en tråd.
Metode 3: Udfør en kørbar med ExecutorService
Fra version 1.5 giver Java en ExecutorService som et nyt paradigme til at oprette og styre tråde inden for et program. Det generaliserer begrebet udførelse af tråd ved at abstrahere oprettelse af tråde.
Dette er fordi du kan køre dine opgaver inden for en pool af tråde lige så let som at bruge en separat tråd til hver opgave. Dette giver dit program mulighed for at spore og styre, hvor mange tråde der bruges til arbejderopgaver.
Antag, at du har 100 arbejderopgaver, som venter på at blive udført. Hvis du starter en tråd pr. Arbejdstager (som præsenteret ovenfor), ville du have 100 tråde i dit program, hvilket kan føre til flaskehalse andre steder i programmet. I stedet for, hvis du bruger en trådpulje med, siger 10 tråde, der er forhåndsdelt, udføres dine 100 opgaver af disse tråde efter hinanden, så dit program ikke sulter efter ressourcer. Derudover kan disse trådpooltråde konfigureres, så de hænger rundt for at udføre yderligere opgaver for dig.
En ExecutorService accepterer a Runnable opgave (forklaret ovenfor) og kører opgaven på et passende tidspunkt. Det Indsend() metode, der accepterer den udførbare opgave, returnerer et eksempel på en kaldet klasse Fremtid, som tillader den, der ringer, at spore opgavens status. Især få() metoden gør det muligt for den, der ringer, at vente på, at opgaven er færdig (og giver eventuelt returkoden).
I eksemplet nedenfor opretter vi en ExecutorService ved hjælp af den statiske metode newSingleThreadExecutor (), som som navnet antyder skaber en enkelt tråd til udførelse af opgaver. Hvis der indsendes flere opgaver, mens en opgave kører, køer ExecutorService disse opgaver til efterfølgende udførelse.
Den kørbare implementering, vi bruger her, er den samme som beskrevet ovenfor.
ExecutorService esvc = Executors.newSingleThreadExecutor (); Løbelig arbejder = ny MyThread2 (sleepFor); Fremtidig fremtid = esvc.submit (arbejder); System.out.printf ("[% s] hovedtråd \ n", Thread.currentThread (). ToString ()); future.get (); esvc.shutdown ();
Bemærk, at en ExecutorService skal lukkes korrekt, når det ikke længere er nødvendigt for yderligere opgaveindgivelser.
Metode 4: En konverterbar brug med ExecutorService
Fra version 1.5 introducerede Java en ny interface kaldet konverterbare. Det svarer til den ældre Runnable interface med den forskel, som eksekveringsmetoden (kaldes) opkald() i stedet for løb()) kan returnere en værdi. Derudover kan det også erklære, at en Undtagelse kan kastes.
En ExecutorService kan også acceptere opgaver, der er implementeret som konverterbare og returnerer a Fremtid med værdien returneret ved metoden ved afslutningen.
Her er et eksempel Mango klasse, der udvider Frugt klasse defineret tidligere og implementerer konverterbare grænseflade. En dyre og tidskrævende opgave udføres inden for opkald() metode.
offentlig klasse Mango udvider Frugt implementerer Callable public Integer call () // dyre beregninger her returnerer nyt heltal (0);
Og her er koden til at indsende en instans af klassen til en ExecutorService. Koden nedenfor venter også på, at opgaven er færdig og udskriver dens returværdi.
ExecutorService esvc = Executors.newSingleThreadExecutor (); MyCallable medarbejder = ny MyCallable (sleepFor); Fremtidig fremtid = esvc.submit (arbejder); System.out.printf ("[% s] hovedtråd \ n", Thread.currentThread (). ToString ()); System.out.println ("Opgave returneret:" + future.get ()); esvc.shutdown ();
Hvad foretrækker du?
I denne artikel lærte vi et par metoder til at skrive flertrådskode i Java. Disse inkluderer:
- Udvidelse af Tråd klassen er den mest basale og har været tilgængelig fra Java 1.0.
- Hvis du har en klasse, der skal udvide en anden klasse i et klassehierarki, kan du implementere Runnable grænseflade.
- En mere moderne facilitet til at oprette tråde er ExecutorService som kan acceptere en Runnable-instans som en opgave at køre. Fordelen ved denne metode er, at du kan bruge en trådpulje til udførelse af en opgave. En trådpool hjælper med ressourcebevaring ved at genbruge tråde.
- Til sidst kan du også oprette en opgave ved at implementere konverterbare interface og indsende opgaven til en ExecutorService.
Hvilke af disse muligheder tror du, du vil bruge i dit næste projekt? Fortæl os det i kommentarerne herunder.