19.1. A Timer és a TimerTask osztály

Ebben a részben az időzítők használatát tárgyaljuk. A Timer osztály a java.util csomag része, a TimerTask osztály példányai ütemezését végzi. Reminder.java egy példa arra, hogy használjuk az időzítőket a késleltetett futtatáshoz:

import java.util.Timer;
import java.util.TimerTask;
public class Reminder {
    Timer timer;
    public Reminder(int seconds) {
        timer = new Timer();
        timer.schedule(new RemindTask(), seconds*1000);
    }
    class RemindTask extends TimerTask {
        public void run() {
            System.out.println("Lejárt az idő!");
            timer.cancel(); //A timer szál megszüntetése
        }
    }
    public static void main(String args[]) {
        new Reminder(5);
        System.out.println("Munka ütemezve.");
    }
}

Indulás után ezt látjuk:
Munka ütemezve.
Öt másodper múlva ezt látjuk:
Lejárt az idő!

A program egy példa arra, hogyan kell példányosítani és ütemezni a szálakat:

  • TimerTask leszármazott osztály példányosítása. A run metódus tartalmazza a futtatás során végrehajtandó kódot. A példába ezt az leszármazott osztály RemindTask-ként neveztük el.
  • Létrehozzuk a Timer osztály egy példányát.
  • Létrehozunk egy időzítő objektumot (new RemindTask()).
  • Beütemezzük az időzítőt. Ez a példa a schedule metódust használja, amelynek paraméterei az időzítő és késleltetés ezredmásodpercben (5000).

Egy másik lehetőség az ütemezésre, hogy az indítási időpontot adjuk meg. Példaképpen a következő kód 23:01-re ütemezi a végrehajtást:

Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 1);
calendar.set(Calendar.SECOND, 0);
Date time = calendar.getTime();
timer = new Timer();
timer.schedule(new RemindTask(), time);

Időzített szálak leállítása

Alapesetben a program addig fut, amíg az időzítő szál is fut. Négy leállítási módszer közül választhatunk:

  • A cancel metódust hívjuk meg. Ezt a program bármelyik pontján megtehetjük, mint a példa run metódusában.
  • Az időzítő szálát démon szállá kell tenni a következőképpen: new Timer(true). Ha a programban csak démon szálak maradnak, akkor a program kilép.
  • Ha befejeződtek az ütemezések, el kell távolítani a Timer objektumhoz tartozó mutatókat. Ezzel a szál is megszűnik.
  • A System.exit metódust hívjuk meg, amely leállítja a programot (benne a szálakat is).

A Reminder példa az első módszert használja, a cancel metódust hívja meg a run metódusból. A démon szálként való létrehozás a példánkban nem működne, mert a programnak futni kell a szál lefutása után is.

19.1.1 Ismételt futtatás

Ebben a példába másodpercenként ismétli a kód futását:

public class AnnoyingBeep {
    Toolkit toolkit;
    Timer timer;
    public AnnoyingBeep() {
        toolkit = Toolkit.getDefaultToolkit();
        timer = new Timer();
        timer.schedule(new RemindTask(),
                       0,        //kezdeti késleltetés
                       1*1000);  //ismétlési ráta
    }
    class RemindTask extends TimerTask {
        int numWarningBeeps = 3;
        public void run() {
            if (numWarningBeeps > 0) {
                toolkit.beep();
                System.out.println("Síp!");
                numWarningBeeps--;
            } else {
                toolkit.beep();
                System.out.println("Idő lejárt!");
            //timer.cancel(); // Nem szükséges
                              // mert van System.exit is.
                System.exit(0);   // Leállítja AWT szálat
                              // (és minden mást)
            }
        }
    }
    ...
}

Futtatás közben ez lesz a kimenet:

Munka ütemezve.
Síp!     
Síp!
Síp!
Idő lejárt!

Az AnnoyingBeep program három paraméteres schedule metódust használ, hogy meghatározza a taszk másodpercenkénti indítását. A Timer metódus változatai:

  • schedule(TimerTask task, long késleltetés, long gyakoriság)
  • schedule(TimerTask task, Date idő, long gyakoriság)
  • scheduleAtFixedRate(TimerTask task, long késleltetés, long gyakoriság)
  • scheduleAtFixedRate(TimerTask task, Date kezdetiIdő, long gyakoriság)

A schedule metódust akkor használjuk, ha a többszörösen futtatott taszk ismétlési ideje számít, a scheduleAtFixedRate metódust, ha az ismétlések időben kötődnek egy pontos időhöz. A példában is a schedule metódust alkalmaztuk, amitől 1 másodperces intervallumokban sípol a gép. Ha valamelyik sípszó késik, akkor a következők is késlekednek. Ha úgy döntünk, hogy a program 3 másodperc múlva kilép az első sípszó után – ami azt is eredményezheti, hogy a két sípszó kisebb időközzel szólal meg, ha késlekedés lép fel – akkor a scheduleAtFixedRate metódust használjuk.