PROCESSPROGRAMMERING
Föreläsning 4 - 17.9.2010
Innehåll:
Högnivå objekt för trådprogrammering:
-Trådgrupper (”Thread pools”)
- Exekverare (Executor och ExecutorService)
Högnivå objekt för
trådprogrammering
Vi har hittils tittat på lågnivå APIn för trådprogrammering som funnits inbyggda i Java
platformen nästan sedan första början.
Trådprogrammering med lågnivå API är lämpligt för mindre program som inte har så
många samtidigt exekverande trådar.
Att skapa ett ny tråd via ett Thread objekt är dock relativt resurskrävande eftersom det
innebär en interaktion med operativsystemet.
Av den orsaken lönar det sej att använda sej av en annan lösning vid programmering av
program som behöver skapa massvis med kortlivade trådar.
Högnivå objekt för
trådprogrammering
Högnivå objekt för samtidighet ”concurrency” har funnits med i Java plattformen sedan
5.0
Dessa högnivåobjekt är resurssnålare än ”lågnivåtrådhantering” och klarar också av att
utnyttja dagens multi-processor system.
Användning av högnivå objekt för programmering av samtidighet innebär i praktiken
användning av trådgrupper (”thread pools”)
Trådgrupper
En trådgrupp består av ett antal inaktiva trådar som är redo att exekvera när som helst.
När en ny tråd behövs i ett program skapar man och startar inte en ny tråd utan man ger
ett Runnable objekt till trådgruppen vartefter en av de inaktiva trådarna aktiveras och
anropar run-metoden.
När run-metoden returnerar (avslutas= stängs inte tråden av utan den hänger kvar som
inaktiv och väntar på följande anrop.
Trådgrupper
En vanlig typ av trådgrupp som användes är fasta trådgrupper (”fixed thread pools”)
Denna trådgruppstyp har alltid ett specifikt antal inaktiva trådar som är redo för
exekvering.
Uppgifter som skall utföras försätts i en kö om alla trådar i trådgruppen är upptagna.
En fördel med att använda en fast trådgrupp är att det hindra ett program som använder
sej av en massa trådar från att krascha (tänk dej en web-server applikation)
Exekverare
Trådgrupper kan användas via en viss typ av objekt som kallas för exekverare
(”executors”)
Java definierar bl.a. gränssnitten, Executor och ExecutorService, som stöder användning
av trådgrupper
Låt oss börja med att titta på gränssnittet Executor.
Gränssnittet Executor erbjuder en ända metod: execute()
Med denna metod kan man ta i bruk en inaktiv tråd i en trådgrupp.
Exekverare: Executor
Om r är ett Runnable objekt skapade man en ny tråd enligt lågnivåmodellen så här:
th = new Thread(r);
th.start();
Vid användning av executors kan koden ovan ersättas med (e är ett objekt av en
Executor):
e.execute(r);
Kodraden ovan är egentligen ganska odefinierad. Vi har berättat att vi vill exekvera
koden i run-metoden av ett Runnable objekt i en tråd men har inte berättat hurdan typ av
tråd.
Exekverare : Executor
Med execute-metoden kan man också köra en uppgift i en egen skapad tråd.
Men vi vill nu kanske hellre använda oss av en tråd ur en trådgrupp för att göra ett
effektivt program.
Java definierar en klass Executors som har ett antal statiska metoder för att skapa
trådgrupper:
newCachedThreadPoos
newFixedThreadPool
newSingleThreadExecutor
newScheduledThreadPool
newSingleThreadScheduledExecutor
Se Java API dokumentationen för närmare info:
http://java.sun.com/javase/6/docs/api/java/util/concurrent/Executors.html
Exekverare : Executor
Man måste alltså börja med att skapa en trådgrupp.
En trådgrupp med ett fast antal trådar kan man skapa m.h.a. den statiska metoden
newFixedThreadPool() i klassen Executors:
Executors.newFixedThreadPool(int nThreads);
ExecutorService
nThreads
Returnerar
= En typ av Executorgränssnitt
= Maxantalet trådar i trådgruppen
= Ett objekt av ett trådgränssnitt (Executor/ExecutorService)
Exekverare : Executor
Exempel: Skaper en trådgrupp på max 10 trådar och för över en uppgift till en tråd i
trådgruppen
class trad implemnts Runnable
{
public void run()
{
System.out.println(”Jag är en tråd!”);
}
...
Executor tradgrupp = Executors.newFixedThreadPool(10) ;
tradgrupp.execute(new Runnable());
}
Exekverare: ExecutorService
Gränssnittet ExecutorService erbjuder mera möjligheter när det gäller trådhantering än
gränssnittet Executor
Några av metoderna i gränssnittet ExecutorService:
submit() =
Används för att överföra koden i run-metdoen av ett Runnable ojbket
till en tråd i en tidigare skapad trådgrupp
shutdown() = Stänger en trådgrupp. Tillåter uppgiter som redan är skickade till
trådgruppen att exekvera färdigt men nya trådar får inte längre
aktiveras
med submit().
shutdownNow() = Stänger av alla aktiva exekverande uppgifter i trådgruppen och
stoppar även kön för väntande uppgifter. Returnerar en lista på de
uppgifter som väntade på att få exekvera.
Exekverare : ExecutorService
Mera detaljer om metoden submit():
Future<?> submit(Runnable task)
Future<T> submit(Runnable task, T result)
Submit() är en överlagrad metod med bl.a. ovannämnda två alternativ. Båda alternativen
tar ett Runnable objekt som parameter och returnerar ett Future – objekt.
Future-objetet kan användas för att kolla olika statusinfo om den exekverande uppgiften,
Se: http://java.sun.com/javase/6/docs/api/java/util/concurrent/Future.html
Exekverare : ExecutorService
Principen för användning av trådgrupper m.h.a. Gränssnittet ExecutorService är
följande:
Anropa en metod, t.ex. newFixedThreadPool i klassen Executors för att skapa en
trådgrupp
Anropa submit för att överföra en uppgift (koden i run-metoden av ett Runnableobjekt) till en tråd i den skapade trådgruppen
Om du vill t.ex. kolla statusinfo eller avbryta en uppgift använd Future-objektets
metoder.
Anropa shutdown() när du inte längre kommer att submittera uppgifter till
trådgruppen, m.a.o. Trådgruppen behövs ej längre
Exekverare : ExecutorService
Future-objektets metoder är:
Cancel()
Get()
=
=
isCancelled() =
isDone()
=
Försöker avbryta en uppgift i denna tråd
Väntar på att tråden skall avslutas och om tråduppgiften
(run-metoden) returnerar ett värde tas det emot i den
formen som specifiserats mellan <>
Returnerar true om uppgiften avbröts före den blev klar
Returnerar true om uppgiften i en tråd är klar