programmera.net -> java -> normal     för utskrift      info@programmera.net

Trådar

1. Trådar
2. Thread
3. Skapa en tråd
4. Deprecated
5. sleep(long [,int])
6. wait()
7. interrupt()
8. notify()
9. join()
10. Prioritet
11. Demoner

1. Trådar

På denna sida beskrivs klassen Thread. Hur man använder trådar beskrivs på sidorna:

2. Thread

Vill man skapa en tråd använder man klassen Thread. Nedan listas de enklaste konstruktorerna:

Konstruktor Beskrivning
Thread()  Konstruktor.
Thread(Str)  Konstruktor där tråden tilldelas ett namn Str.
Thread(Obj)  Konstruktor där tråden associeras med ett object Obj, där Obj måste implementera Runnable.
Thread(Obj,Str)  Konstruktor där tråden associeras med ett object Obj, där Obj måste implementera Runnable. Str är trådens namn.

Nedan listas några av de metoder man använder för att kontrollera tråden:

Metod Statisk Try-Catch Beskrivning
run()  Nej  Nej  Denna metod gör ingenting.
start()  Nej  Nej  Startar tråden, dvs kör trådens run(). Men, om tråden har ett associerat objekt startar tråden metoden run() hos objektet istället.
sleep(long [,int])  Ja  Ja  Får tråden att sova i long millisekunder plus int nanosekunder.
yield()  Ja  Nej  Tråden låter JVM köra någon annan tråd.
interrupt()  Nej  Ja  Väcker en tråd.
wait()  Nej  Ja  Anropas på ett objekt. Metoden placerar tråden i objektets monitors fördröjningslista tills någon annan tråd anropar notify() på objektet.
wait(long [,int])  Ja  Ja  Anropas på ett objekt. Fördjöjs maximalt long millisekunder plus int nanosekunder.
notify()  Nej  Nej  Anropas på ett objekt. Frigör någon tråd från objektets fördröjningslista.
notifyAll()  Nej  Nej  Anropas på ett objekt. Frigör alla trådar från objektets fördröjningslista.
join()  Nej  Ja  Exekveringen blockeras tills tråden vars join man anropar har dött.

Nedan listas några metoder för att kontrollera trådens status, ingen av dessa är statiska eller kastar några undantag:

Metod Beskrivning
setDeamon(boolean)  Förvandlar tråden till eller från att vara en demon.
isDeamon()  Kollar om tråden är en demon.
isAlive()  Kollar om tråden lever.
holdsLock(Obj)  Kollar om tråden låser objektet Obj.
setName(Str)  Sätter trådens namn till Str.
getName()  Returnerar trådens namn.
setPrioritet(int)  Sätter trådens prioritet till int (1 till 10).
getPriority()  Returnerar trådens prioritet.

3. Skapa en tråd

Det finns två sätt att skapa en tråd:

  • Associera ett objekt som implementerar Runnable (har metoden run()) med en tråd. Detta görs med konstruktorn Thread(Obj [,Str]). Fördelen med denna metod är att objektet som innehåller run() inte behöver ärva från Thread.
  • Skapa ett objekt som ärver av Thread och överrider metoden run(). Fördelen med att ha en objekt som representerar en tråd är att Thread kan behandlas som vilket objekt som helst, till och med sparas.
Följande exempel visar hur den andra metoden fungerar:
class TestExtendThread{
  public static void main(String[] args){
    MyThread t1=new MyThread("Nr 1");
    MyThread t2=new MyThread("Nr 2");
    t1.start();
    t2.start();
  }
}

class MyThread extends Thread{
  MyThread(String s){
    super(s);
  } 
  public void run(){
    System.out.println("Name="+this.getName());
  }
}
Detta är en möjlig utskrift av programmet:
[olle@dev1]$ java TestExtendThread
Name=Nr 2
Name=Nr 1
Trådarna Nr 1 och Nr 2 kan köras i vilken ordning som helst av JVM.

4. Deprecated

Det finns några metoder i Thread som numera är deprecated vilket betyder att Sun starkt avråder från att man ska använda dem. De måste dock finnas kvar i 1.4 för bakåtkompabilitetens skull. Dessa metoder är bra att känna till, eftersom de ger en ledtråd i hur de nya metoderna ska användas:

  • stop() Denna metod dödar en tråd. Denna metod bör inte användas eftersom objekt ibland kan hamna i ett inkonsistent tillstånd när en tråd dödas utifrån. När detta händer säger man att objektet har blivit skadat. Att upptäcka att ett objekt är skadat kan vara mycket svårt, och beteendet hos ett skadat objekt är odefinierat.
  • suspend() Denna metod blockerar en tråd tills man anropar resume(). Problemet med denna metod är att om en tråd som har låst en viktig resurs suspenderas behålls resursen låst. Detta leder ofta till deadlock.
  • resume() Denna metod väcker en tråd som har blockerats med suspend(), se ovan.
Istället för suspend() ska tråd1 sätta en flagga hos tråd2. Detta innebär att man önskar att tråd2 ska blockeras. Regelbundet kollar tråd2 om flaggan är satt, och om så är fallet anropas wait(). Fördelen med detta sätt är att wait() anropas inifrån, så tråden blockerar sig själv. Nu kan vi se till att tråd2 blockeras vid tillfällen då den inte har låst något viktigt objekt.

5. sleep(long [,int])

Denna metod får den anropade tråden sova i long millisekunder plus int nanosekunder. När tråden sover låter JVM någon annan tråd köra, om det finns någon.

  • En tråd kan bara anropa sleep() på sig själv.
  • Metoden kastar InterruptedException och måste anropas inom ett try-catch-block.
  • Tråden kan väckas genom att någon annan tråd anropar anropar interrupt() på den sovande tråden. Då kastas undantaget InterruptedException och tråden går in i catch-blocket.
  • Eftersom metoden är statisk går den att använda även i icke trådade applikationer.
Här kommer ett exempel:
class TestSleep{
  public static void main(String[] args){
    System.out.println("Go to sleep!");
    try{
      Thread.sleep(2000);
    }catch(InterruptedException ie){
       System.out.println("sleep IE!");
    }
    System.out.println("Awake!");
  }
}
Vi kör programmet:
[olle@dev1]$ java TestSleep
Go to sleep!
Awake!

6. wait()

Denna metod finns egentilgen inte i klassen Thread utan används av objekten för att fånga körande trådar. Alla objekt kan använda wait() eftersom metoden finns i basklassen Object. Java fungerar så att varje objekt har en monitor med en fördröjningslista. Med wait() kan man få en enskild tråd att skickas till objektets monitors fördröjningslista. Om en tråd exekverar objekt1.wait(); är tråden låst tills någon annan tråd exekverar objekt1.notify();. Följande regler gäller för wait():

  • En tråd kan bara anropa wait() på sig själv.
  • När wait() anropas måste objektet vara låst, därför måste wait() anropas inom ett synchronized-block. Kompilatorn bryr sig visserligen inte om att du anropar metoden utanför ett synchronized-block, men IllegalMonitorStateException kastas under körningen.
  • wait() anropas låser tråden upp objektet och låter andra trådar använda objektet.
  • Tråden kan väckas genom att någon annan tråd anropar notify() eller notifyAll() på objektet. Tråden är nu blockerad och väntar på att få låsa objektet så den kan fortsätta köra.
  • wait() kastar InterruptedException och måste anropas inom ett try-catch-block.
  • Tråden kan väckas genom att någon annan tråd anropar interrupt() på den sovande tråden. Tråden är nu blockerad och väntar på att få låsa objektet så den kan fortsätta köra och ta hand om undantaget.
Läs mer på sidan  villkorssynkronisering .

7. interrupt()

Med denna metod kan man påverka blockerade trådar. Vi får tre fall:

  • Om tråden sover så kastar den InterruptedException och går in i catch-blocket.
  • Om tråden är fördröjd så kastar den InterruptedException och går in i catch-blocket.
  • Om tråden är blockerad av en kanal som kan fånga ClosedByInterruptedException, stängs denna kanal och undantaget kastas.

8. notify()

Denna metod väcker maximalt en tråd ur objektets fördröjningslista. Om listan innehåller flera trådar vet man inte vilken som väcks.

  • När tråden försöker väcka en tråd måste den låsa objektet, därför måste notify() anropas inom ett synchronized-block.
Läs mer på sidan  villkorssynkronisering .

9. join()

Med denna metod blockeras tråden tills en annan tråd har avslutats. Om man har flera trådar körande kanske man vill vänta tills alla är klara innan man fortsätter.

  • join() kastar InterruptedException och måste anropas inom ett try-catch-block.
I följande exempel väntar main() på att tråden st ska dö:
public class TestJoin{
  public static void main(String[] args){
    Sleeper s=new Sleeper();
    s.start();
    try{
      s.join();
    }catch(InterruptedException ie){
       System.out.println("Join IE!");
    }
    System.out.println("main die!");
  }
}

class Sleeper extends Thread{
  public void run(){
    System.out.println("Sleeper sleep!");
    try{
      sleep(2000);
      System.out.println("Sleeper awake!");
    }catch(InterruptedException ie){
      System.out.println("Sleeper IE");
    }
    System.out.println("Sleeper die!");
  }
}
En körning av programmet ger följande utskrift:
[olle@dev1]$ java TestJoin
Sleeper sleep!
Sleeper awake!
Sleeper die!
main die!

10. Prioritet

Det anses god vana att använda konstanterna MAX_PRIORITY (=10), NORM_PRIORITY (=5) och MIN_PRIORITY (=1) istället för ett tal mellan 1 till 10. Dessa konstanter finns i klassen Thread. Man brukar sätta låg prioritet på trådar som kör länge och hög prioritet på trådar som sköter användarinmatning, annars tror användaren att programmet har hängt sig. När en tråd skapas ärver den förälderns prioritet.

11. Demoner

Att sätta en tråd till att vara demon innebär i praktiken att programmet kan avslutats trots att demontråden fortfarande lever. Namnet antyder att tråden sysslar med bakgrundssysslor som användaren inte direkt märker.