Richtiges Warten

eclipseworker

Bekanntes Mitglied
Ich habe folgenden Code um ein wichtiges Verhalten zu simulieren: verzögerter Erzeuger aufgerufen im Main:
Java:
public class MainClass {
 
  public static class Waiter implements Runnable{
      private int ses=0;
      public void run(){
        try{
          new Thread().sleep(500);
        }catch(InterruptedException i){
          i.printStackTrace();
        }
          ses=1;
          notifyAll();
      }
     
      public int getSes(){
          return ses; 
      }
  }
    public static void main(String[] args) {
      try{
          Waiter w=new Waiter();
          Thread wt=new Thread(w);
         // Object o=new Object();
          wt.start();
          synchronized (wt){
          wt.wait();}
          System.out.println(w.getSes());
      }catch(InterruptedException i){
          i.printStackTrace();
 
      }
    }
}
nun der code gibt wie erwartet 1 aus, aber hat auch eine IllegalMonitorStateException wie komme ich da herum? Außerdem ich habe mehrere Threads die sich einen Waiter erzeugen und auf das Result ihres eigenen Waiters warten, wie stelle ich sich, dass ein Threat der von einem anderen Waiter aufgeweckt wurde weiter schläft? Ich habe schon überlegt eine Boolsche Variable zusetzen, aber das scheint mir zu unsicher.
 
Gib dem Waiter doch ein Interface und rufe dort dann waiterHasFinished() oder sowas auf.

Gruß

Claus
Eigentlich wollte ich Bussywaiting vermeiden und das an Java delegieren.
Ich meine ja
Java:
public interface Waitinterface{
    public boolean isFinished();
}
und dann
in der Main Klasse:
Java:
Waiter w=new Waiter();
Thread wt=new Thread(wt);
wt.start();
while(!w.isFinnished());
System.out.println(w.getSes());
//arbeite weiter
wäre ein Lösung, ich suche aber ein etwas bessere.
 
Zuletzt bearbeitet:
nun der code gibt wie erwartet 1 aus, aber hat auch eine IllegalMonitorStateException wie komme ich da herum?
Indem du die Doku der aufgerufenen Funktionen beachtest, weshalb die Exception geschmissen wird, steht dort beschrieben 😉

https://docs.oracle.com/javase/10/docs/api/java/lang/Object.html#notifyAll() hat gesagt.:
IllegalMonitorStateException - if the current thread is not the owner of this object's monitor.



Ich meine ja
Java:
public interface Waitinterface{
    public boolean isFinished();
}
und dann
in der Main Klasse:
Java:
Waiter w=new Waiter();
Thread wt=new Thread(wt);
wt.start();
while(!w.isFinnished());
System.out.println(w.getSes());
//arbeite weiter
wäre ein Lösung, ich suche aber ein etwas bessere.
Mit der Variante stößt du u.U. auf weitere Probleme. Beide beteiligten Threads können je nach Umsetzung die finished-Variable cachen, und bekommen von Änderungen des andere Threads nichts mit, wodurch das eine Endlosschleife produziert.

Falls du aber Spin-Locks nutzen willst, kannst du der JVM helfen, und Thread.onSpinWait nutzen.

Eigentlich wollte ich Bussywaiting vermeiden und das an Java delegieren.
In java.util.concurrent gibts einen Haufen Klassen, die die low-level-Dinge kapseln und das für den Entwickler vernünftig nutzbar machen. Für die meisten Fälle gibts da was passendes - in deinem Fall könnte schon ExcecutorService reichen 😉
 
Zuletzt bearbeitet:
Eigentlich wollte ich Bussywaiting vermeiden und das an Java delegieren.
Ich meine ja
Java:
public interface Waitinterface{
    public boolean isFinished();
}
und dann
in der Main Klasse:
Java:
Waiter w=new Waiter();
Thread wt=new Thread(wt);
wt.start();
while(!w.isFinnished());
System.out.println(w.getSes());
//arbeite weiter
wäre ein Lösung, ich suche aber ein etwas bessere.

Sorry mein Fehler. Ich meinte natürlich einen Listener und kein Interface.
 
Indem du die Doku der aufgerufenen Funktionen beachtest, weshalb die Exception geschmissen wird, steht dort beschrieben 😉
Ok danke, dass ändert aber nicht an meinen Problem, dass ich in der Mainklasse warten muss da dort das Erzeugnis gebraucht wird. Und Executor Service ist auch eher unangebracht, da ich eher das Programm 10 mal oder so sperat starte.
Ok vielleicht beginne ich von vorne:
ich soll ein Peer-Netzwerk simulieren und der relevante Code in der Node ist folgender:
Java:
Socket newConnection=serverSocket.accept();
                  String connectionAddress=newConnection.getInetAddress().getHostAddress();
                  int connectionPort=newConnection.getPort();
                  LineAdded addStat=table.addnewLine(new NodeTableLine(connectionAddress, connectionPort, "tempmname"+tnc), increase, replaceLine);
                  NodeAnswerMaschine ans=new NodeAnswerMaschine(newConnection, table);
                  Thread ansThread=new Thread(ans);
                  ansThread.start();
                  ansThread.wait();
                  NodeTable tableAnsweredWith=ans.getRecived();
                  table.merge(tableAnsweredWith, false);
also kurz wird eine Verbindung aufgebaut ist diese von einem anderen Knoten, er schickt mir seinen NoteTable und ich und ich ihm seinen, nun richtig wäre es ein Knoten pro Gerät, ich habe aber nur ein Gerät und muss es auf dem machen.
Und so sende ich die Table (etwas unterhalb diesem Empfangscode):
Java:
Thread.sleep(sleep);
                  NodeTableLine rl=table.returnRandomLine();
                  String rlAddress;
                  int rlPort;
                  if(rl.getConcetedVia().equals(NodeTableLine.direct)){
                      rlAddress=rl.getAddress();
                      rlPort=rl.getPort();
                  }else{
                      rlAddress=rl.getConcetedVia().split(":")[0];
                      rlPort=Integer.getInteger(rl.getConcetedVia().split(":")[1]);
                  }
                  try(Socket socket = new Socket(rlAddress, rlPort);
                    ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());){
                        out.writeObject(table);
                        out.flush();
                        socket.close();
                      }catch (IOException e) {
 
Ok danke, dass ändert aber nicht an meinen Problem, dass ich in der Mainklasse warten muss da dort das Erzeugnis gebraucht wird.
Inwiefern ist das ein Problem? Oben steht ein völlig anderes...
Und Executor Service ist auch eher unangebracht, da ich eher das Programm 10 mal oder so sperat starte.
Für das oben beschrieben ist das durchaus eine mögliche Lösung...

Wenn du das *Programm* allerdings separat startest, hat das nicht mehr viel mit Threads zu tun, sondern du musst verschiedene Prozesse synchronisieren, das ist eine völlig andere Baustelle.


Thread ansThread=new Thread(ans);
ansThread.start();
ansThread.wait();
Dieses Pattern (Ausführung asynchron starten, auf Ende warten, Ergebnis abholen) ist einer der Anwendungsfälle, der ziemlich gut für ExcecutorService in Verbindung mit Callable und Future geeignet ist.
Warum sollte das nicht gehen?


Warum das bei deinem Problem völlig ungeeignet ist, versteh ich anhand deiner Erklärung nicht...
 
Das Programm sollte auch über ein richtiges Netzwerk funktionieren, also würde ein Executehandler mit einem Task gestartet.
Und...?

nd wie das Callable es besser macht erschließt sich mir nicht.

Dein obiges Programm wird damit zu einem:
Code:
public class MainClass {
 
public static void main(String[] args) throws Exception {
        WaiterTask w = new WaiterTask();
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<Integer> ses = executor.submit(w);
        System.out.println(ses.get());
    }

    public static class WaiterTask implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
            Thread.sleep(500);
            return 1;
        }
    }
}

Ganz ohne irgendwelche händische Synchronisierung
 

Zurück
Oben