Wait(), notify() ?

Hallo an alle,

ich habe folgendes Problem:

ich habe ein Hauptthread (Th-1), der einen zweiten Thread (Th-2)
startet. (Th-2) soll dabei in einer while-Schleife laufen. Am Ende der
Schleife soll sich der Thread immer in den “wait()”-Modus versetzen,
also schlafen legen. (Th-2) soll solange schlafen bis (Th-1) notify()
aufruft. Dann beginnt bei Th-2 der nächste Schleifen durchlauf.

Zur Anmerkung: Beide Threads sind derzeit in einer Klasse.

Von der Theorie denke ich habe ich das Problem soweit gut verstanden,
nur habe ich Probleme bei der Umsetzung. Es gelingt mir zwar Th-2 mit
wait schlafen zu legen, jedoch nicht aufzuwecken.

Ich hoffe, dass mir jemand helfen kann.

Viele Grüße und vielen Dank im Voraus,

drucker

Um das Schlafen hast du ein try-catch?

        try {
            Thread.sleep(milliSeconds);
        }
        catch (InterruptedException e) {
            // tu was!
        }

Ich vermute mal du rufst wait() und notify() auf unterschiedlichen Objekten auf. In der Java Insel ist das ziemlich gut beschrieben.

ich möchte den Thread nicht mit sleep() schlafen legen, sondern mit wait().

Bei wait() wird zunächst die Sperre freigegeben (dies ist mit sleep() bekanntlich nicht möglich) und dann der Thread in den

Wartezustand versetzt. Der Thread kann nur durch ein notify() oder ein notifyAll()

auf dieses Objekt wieder freigegeben werden (bzw. durch zeitbegrenztes wait())

soweit zur Theorie :slight_smile:

Falls mir jemand bei der umsetzung helfen könnte, wäre ich ihm sehr dankbar

Den Hinweis von Lumaraf berücksichtigt?
Grundsätzlich funktionioniert das ja so. Daher: Wie ist das im Code implementiert?

Hallo Lumaraf,

Das Objekt mit dem ich wait und notify aufrufe ist der Thread-2.

Runnable _runnable_commRunnableRX = new Runnable() 
{
    @Override
    public void run() {
        while (true)
        {
            ct++;
            if(ct == 1)
            {
                start();
            }
            else
                resume();
        }
    }
};

public void start()
{
    thread__GUI_RT_intervall_wait = true;
    thread__GUI_RT_intervall = new Thread(null,_runnable_commRunnableGUI_RT_intervall , TAG);
    thread__GUI_RT_intervall.start();
}

public void resume()
{
    synchronized (thread__GUI_RT_intervall)
    {
        thread__GUI_RT_intervall_wait = false;
        thread__GUI_RT_intervall.notify();
    }
}

Runnable _runnable_commRunnableGUI_RT_intervall = new Runnable() {
    @Override
    public synchronized void run() {

        runOnUiThread(new Runnable() {

            @Override
            public void run() {
                while (thread__GUI_RT_intervall == Thread.currentThread()) {
                    //Grafische Ausgabe

                    synchronized(thread__GUI_RT_intervall) {
                        while(thread__GUI_RT_intervall_wait) {
                            try {
                                this.wait();
                            } catch (InterruptedException e) {
                            }
                        }
                    }
                }
            }
        });
    }    
};

Uups, da ist wohl etwas mit der Formatierung schief gegangen…
Poste am besten eine kompilierbares Testprogramm (mit lesbaren Variablenbezeichneren)

Wenn ich das richtig überblicke rufst Du wait() und notify() an jeweils unterschiedlichen Objekten auf. wait am Runnable und notify am Thread der das Runnable ausführt.

Sooo, ich habe mal versucht das alles in eine neue Klasse unter Java direkt zu packen. Es ist leider nicht so kompilierbar, da es für Android geschrieben ist (da gibt es den extra Thread/Runnable runOnUiThread(new Runnable() {})
Ich hoffe es hilft euch weiter.



public class test {

    static long counter=0;
    static Thread threadRX;
    static Thread thread__GUI; 
    
    static boolean thread__GUI_wait;
    /**
     * @param args
     */
    public static void main(String[] args) 
    {

        threadRX = new Thread(null, _runnable_1, "TAG");    
        threadRX.setDaemon(true);     //sorgt dafür, dass dieser Thread mit beenden des Hauptprogramms beendet wird
                                    // Diese Methode ist nur vor dem STart des Threads erlaubt
        threadRX.start();

    }
    

    static Runnable _runnable_1 = new Runnable() 
    {
        @Override
        public void run() 
        {
            while (true) 
            {
                counter++;
                if(counter == 1)
                {
                    start();
                }
                else
                    resume();
            }
        }
    };
    
    public static void start() 
    {
        thread__GUI_wait = true;
        thread__GUI = new Thread(null,_runnable_commRunnableGUI_RT_intervall, "TAG");
        thread__GUI.start();
    }
    public static void resume() 
    {
        synchronized (thread__GUI)
        {
            thread__GUI_wait = false;
            thread__GUI.notify();
        }
    }
    
    static Runnable _runnable_commRunnableGUI_RT_intervall = new Runnable() 
    {
        @Override
        public synchronized void run() 
        {
                runOnUiThread(new Runnable() 
                {
                    @Override
                    public void run() 
                    {
                        while (thread__GUI == Thread.currentThread()) 
                        {
                            synchronized(thread__GUI) 
                            {
                                while(thread__GUI_wait) 
                                {
                                    try 
                                    {
                                        thread__GUI.wait();
                                    } catch (InterruptedException e) 
                                    {
                                    }
                                }
                            }
                        }
                    }
                });
        }        
    };
                        
}



Ist denn diese Bedingung jemals erfüllt? In dem Code ist nichts zu sehen, dass dieser Thread dieses Runnable ausführt (abgesehen, davon dass der Thread bereits eine anderes Runnable (_runnable_commRunnableGUI_RT_intervall) ausführt und danach eigentlich „tot“ ist).
Wo wird thread__GUI_wait jemals wieder true - außer in start?

Wenn es für Android ist, warum nutzt nicht die Android spezifischen Mechanismen wie Handler, AsyncTasks… ? Was versuchst Du da zu implementieren? Evlt. gibt es da bessere Wege.

mhhh du scheinst recht zu haben… also, dass was ich versuche zu implementieren ist folgendes:

Ein Thread der die grafische Ausgabe macht/aktualisiert, soll in einer endlosschleife laufen und nach jedem durchlauf sich schlafen legen bis er extern getriggert wird, dann arbeitet der Thread weiter. der Externe Trigger soll in einem Thread erfolgen der umfangreiche Berechnung vornimmt. erst wenn neue Ergebnisse vorliegen soll es auf der GUI geupdatet werden. Deswegen der Ansatz mit wait() und notify().

Wenn es also einfach nur darum geht an bestimmten Punkten ein Update des UI durchzuführen, dann nutze z.B. einen Handler:

  1. Erstelle einen Handler und überschreibe dessen handleMessage(Message msg) in dieser Methode implementierst Du den UI Update.
  2. Sorge dafür, dass Du innerhalb des Rechenthreads bzw. in der run des Runnables (hier kannst Du weiterhin Thread & Runnable nutzen) auf das Handler Objekt zu greifen kannst.
  3. Immer wenn aus dem Thread heraus eine Update des UI angestossen werden soll rufst Du handler.sendEmptyMessage(0); am Handler Objekt auf. Da ja nur ein Update angestossen werden soll, sollte eine EmptyMessage für den Zweck ausreichen. )Ansonsten bietet Handler noch weitere Methoden sendMessage, post…)

Je nachdem was genau Du da machst solltest Du Dir evtl. auch mal das Thema Service anschauen.

Vielen Dank für deine Anregungen.

Mit einem Handler habe ich bisher noch nicht gearbeitet. Nun werde ich mich damit mal beschäftigen :slight_smile:
kurze Frage dazu: ist der Handler eine Referenz auf den UI-Thread? oder wie darf ich ihn ganz grob verstehen (nur damit ich eine Vorstellung davon bekomme)?

Viele Grüße,

drucker

So ganz grob: Die Methode handleMessage wird in dem Thread ausgeführt in dem der Handler erzeugt wurde. Das muss nicht unbedingt der UI -Thread sein.
Wenn Du aber den Handler im UI Thread erzeugst ist das ähnlich dem SwingUtilities.invokeLater unter Swing, vor allem die post Variante lässt gewisse Parallitäten erkennen.