Java Methode zu bestimmter Uhrzeit starten

Crashdowns

Ensign
Registriert
Juni 2010
Beiträge
138
Nabend Leute,
ich arbeite an einem kleinen Programm das mehrere Wochen auf einem Server laufen soll und zu 6 verschiedenen Tageszeiten eine bestimmte Methode starten soll. Die Ausführung der Methode dauert dann ca 15min. Danach soll das Programm dann im Idle warten bis die nächste Ausführungszeit erreicht ist. Ich habe über google bereits die Timer Class gefunden, konnte das jedoch nicht richtig auf meine Bedürfnisse anpassen. Fällt euch noch eine andere Variante ein bzw. hat jmd ein Tutorial zur Hand in dem mein Fall ungefähr behandelt wird?

Cheers und schonmal danke!

crash:D
 
Eine Möglichkeit wäre:
- Nehme dir eine Priority Queue (z.B. realisiert durch einen Heap)
- Verwende den Timestamp, wann die Methode ausgeführt werden soll, als Key. Damit befindet sich die Methode, die als erstes aufgerufen werden soll immer an der Wurzel des Heaps.
- Prüfe in regelmäßigen Abständen (z.B. 6 mal am Tag), ob der Timestamp der Wurzel erreicht wurde -> aufrufen und aus Heap entfernen
 
Muss das Programm denn die ganze Zeit laufen? Oder kann es auch einfach zu den gewünschten Zeiten gestartet werden, die Methode ausführen und sich dann wieder beenden?
Dann könntest du nämlich Cron benutzen, oder was ähnliches je nach Betriebssystem.
 
@sacridex
das programm muss die ganze zeit laufen, da es nebenbei noch andere aufgaben erledigt.

@kinglouy
bei deiner lösung stehe ich ja wieder vor dem problem das ich zu bestimmter zeit abfragen muss ob der timestamp erreicht ist. Und andauernd per while schleife abfragen will ich nicht. Oder habe ich dich falsch verstanden?

@Tumbleweed
quartz hatte ich schonmal im blick, wollte aber gucken ob es auch mit java built in geht;)
 
Crashdowns schrieb:
@kinglouy
bei deiner lösung stehe ich ja wieder vor dem problem das ich zu bestimmter zeit abfragen muss ob der timestamp erreicht ist. Und andauernd per while schleife abfragen will ich nicht. Oder habe ich dich falsch verstanden?

Hätte ich mit Thread.sleep() gemacht, wenn bekannt ist, wann in etwa abgefragt werden muss. Es müsste ja nur die Differenz zwischen der aktuellen Zeit und dem Zeitpunkt, wann aufgerufen werden soll, gebildet werden. Schon weißt du, wie lange der Thread warten muss.
Dass Polling nie optimal ist, ist mir schon klar. War nur eine einfache Lösung, die mir spontan eingefallen ist.
 
Hi!

Kurzes Beispiel, wie man es lösen könnte.
Kurz gefasst haben wir zwei Threads. Einer davon ist nur dafür zuständig, den anderenThread jede Sekunde aufzuwecken, damit der überprüfen kann, ob's was zum Arbeiten gibt. Dafür überprüft er für eine beliebige Anzahl von Tageszeiten, ob eine davon schon überschritten ist und fängt an zu arbeiten.

Liebe Grüße!

Example.java

Code:
public class Example {

    // ===================================================================
    // {[> Initializers and Constructors
    // =================================
    public Example() {
        final Object threadMonitor = new Object();
        new WorkerThread(threadMonitor);
        new PollerThread(threadMonitor);
    }


    // ===================================================================
    // {[> Public Static Methods
    // =========================
    public static void main(String[] args) {
        new Example();
    }
}
TimeOfDay.java
Code:
public class TimeOfDay {

    // ===================================================================
    // {[> Attributes
    // ==============
    private final int h, m, s;



    // ===================================================================
    // {[> Initializers and Constructors
    // =================================
    public TimeOfDay(int hour, int minute, int second) {
        h = hour;
        m = minute;
        s = second;
    }



    // ===================================================================
    // {[> Public Methods
    // ==================
    public final boolean isAfter(GregorianCalendar gc) {
        int hour = gc.get(Calendar.HOUR_OF_DAY);
        int minute = gc.get(Calendar.MINUTE);
        int second = gc.get(Calendar.SECOND);
        
        if (hour > h) {
            return true;
        } else if (hour == h) {
            if (minute > m) {
                return true;
            } else if (minute == m) {
                if (second > s) {
                    return true;
                }
            }
        }

        return false;
    }
}
PollerThread.java
Code:
public class PollerThread extends Thread {

    // ===================================================================
    // {[> Attributes
    // ==============
    private final Object threadMonitor;



    // ===================================================================
    // {[> Initializers and Constructors
    // =================================
    public PollerThread(Object threadMonitor) {
        this.threadMonitor = threadMonitor;
        start();
    }



    // ===================================================================
    // {[> Public Methods
    // ==================
    public void run() {
        while (true) {
            try {
                sleep(1000);
            } catch (InterruptedException e) {}

            synchronized (threadMonitor) {
                threadMonitor.notifyAll();
            }
        }
    }
}
WorkerThread.java
Code:
public class WorkerThread extends Thread {

    // ===================================================================
    // {[> Attributes
    // ==============
    private final Object threadMonitor;
    private final TimeOfDay[] times;

    private int step = 0;



    // ===================================================================
    // {[> Initializers and Constructors
    // =================================
    public WorkerThread(Object threadMonitor) {
        this.threadMonitor = threadMonitor;

        this.times = new TimeOfDay[6];
        this.times[0] = new TimeOfDay(0, 0, 0);
        this.times[1] = new TimeOfDay(4, 0, 0);
        this.times[2] = new TimeOfDay(8, 0, 0);
        this.times[3] = new TimeOfDay(12, 0, 0);
        this.times[4] = new TimeOfDay(16, 0, 0);
        this.times[5] = new TimeOfDay(20, 0, 0);

        start();
    }



    // ===================================================================
    // {[> Public Methods
    // ==================
    public void run() {
        GregorianCalendar gc;

        while (true) {
            synchronized (threadMonitor) {
                try {
                    threadMonitor.wait();
                } catch (InterruptedException e) {}
            }

            gc = new GregorianCalendar();
            if (times[step].isAfter(gc)) {
                System.out.println("work: " + step);
                step = (step + 1) % times.length;
            }
        }
    }
}
 
Was spricht denn gegen ein simples
Code:
		ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
		// Berechnung der Zeitdifferenz
		executor.scheduleAtFixedRate(new Runnable()
		{
			@Override
			public void run()
			{
				// call method
			}
		}, initialDelay, period, TimeUnit.SECONDS);
wobei initialDelay einfach die Differenz von Programmstart und erster Ausführung ist und die period dann 4h.
Und wenn man mit Zeiten hantiert, ist Joda-Time empfehlenswert. Erspart viel Arbeit und ist gut lesbar.
 
@Tumbleweed
Die Lösung wäre einfach und elegant, leider soll das Programm nicht 6mal am Tag im 4h Abstand gestartet werden, sondern nur zu 6 bestimmten Uhrzeiten (8:00, 9:00, 12:00, 16:00, 18:00, 21:00).
@Killkrog
Ist auch wieder eine Polling basierte Lösung, werde ich aber im Hinterkopf behalten falls sich aus den anderen Idee nichts ergbit. Da ich morgen eine Prüfung schreibe bin ich nocht nicht dazu gekommen alle Vorschläge auszutesten (nach einer oberflächlichen Betrachtung könnte Quartz das Problem ja ggf. lösen).

Weitere Idee und Vorschläge sind stets Willkommen.
 
Zuletzt bearbeitet:
Sei doch mal kreativ!

Code:
	private static int index;
	final static long[] executionTimeDifferences = new long[] { 60, 180, 240, 120, 180, 660 };
	final static ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
	
	private static int determineFirstIndex() {
		// find start index here
		return 2;
	}
	
	private static class RepetitiveTask implements Runnable
	{
		@Override
		public void run() {
			// call your method
			
			if (++index >= executionTimeDifferences.length) {
				index = 0;
			}
			executor.schedule(new RepetitiveTask(), executionTimeDifferences[index], TimeUnit.MINUTES);
		}
	}
	
	public static void main(String[] args) {
		executor.schedule(new RepetitiveTask(), executionTimeDifferences[determineFirstIndex()], TimeUnit.MINUTES);
	}
Erhebt keinen Anspruch auf Vollständigkeit und/oder Richtigkeit. Ein bisschen grübeln sollst du ja auch. :p
 
Zuletzt bearbeitet:
Ich glaube, um Polling wirst du nicht drum rum kommen. Ich schätze mal, auch wenn ich es nicht genau weiß, dass Quartz intern das selbe Prinzip benutzen muss. Außer es geht nativ auf die OS Events los...
Lasse mich gerne eines besseren belehren!

Ergänzung:
Hmm, kaum denkt man ein wenig über seinen eigenen Post nach, kommt man auf neue Ideen :D
Das hier wäre auch eine Möglichkeit ohne Polling...

Code:
public static final void sleepUntil(Calendar date) throws InterruptedException {
    Thread.sleep(Math.max(date.getTimeInMillis() - System.currentTimeMillis(), 0));
}
 
Zuletzt bearbeitet:
Habe jetzt den letzten Vorschlag von Killkrog umgesetzt. War simple und einfach nachvollziehbar für nachfolgende Nutzer.
Danke für die Hilfe Leute!
 
Zurück
Oben