2011-01-05 6 views
1

Hier ist ein Ausschnitt aus einem Web-Server, die ich zur Zeit bin Gebäude ...Peculiar Verhalten mit mehreren Threads/volatile Variablen/conditionals/Schleifen (Java)

// ...

threadPool = Executors.newCachedThreadPool(); 
while (true) 
    if(this.isOn) { 
       try { // listen for incoming connection 
       this.clientSocket = serverSocket.accept(); 
     } catch (IOException e) { 
        System.err.println("LOG: >> Accept failed! "); 
        System.exit(1); 
        } 
     // as soon as a connection is established send the socket 
     // with a handler/processor to the thread pool for execution 

        threadPool.execute(new ClientRequestProcessor(clientSocket)); 
     } 

// ...

Bitte beachten Sie, dass die isOn Variable ein VOLATILE boolean ist.

Wenn ich das in eine Weile mache ... funktioniert dieser Code ... aber so wie es ist, tut es nicht. Darf ich fragen warum? Aus logischer Sicht sollten beide funktionieren, auch wenn ich diese Flagge in einem if teste ... verpasse ich etwas ?!

[Spätere Bearbeitung:] Durch die nicht funktioniert meine ich ... ein Browser (z. B. Firefox) kann nicht verbinden, tatsächlich versucht es, aber Timeout schließlich. Wenn ich das in eine Weile (isOn) ändere, funktioniert es wie ein Zauber.

Alle Vorschläge/Ideen sind mehr als willkommen !!!

P.S. Ich brauche diese Kombination "while (true) if/while (Testflag) {...}" weil der Server von einer GUI aus gestartet/gestoppt werden kann ... also die oberste Ebene while (true) wird benötigt, damit ich kann überprüfen, ob ich eingeschaltet bin (und damit auf Verbindungen höre) oder ob ich ausgeschaltet bin (und sich nicht wirklich um eingehende Verbindungen kümmern). Die Event-Handler der GUI können die Flagge jederzeit ändern.

Antwort

2

Eine bessere Lösung ist, den Server-Socket zu schließen, wenn Sie es stoppen und einen neuen in einem neuen Thread starten möchten, wenn Sie es starten möchten. Auf diese Weise lehnen Sie neue Verbindungen ab und verbrauchen keine CPU, wenn sie nichts unternimmt.

Wenn isOn == true und Sie es falsch drehen, wird es nur Verbindungen nach der nächsten neuen Verbindung nicht akzeptieren. (Kann jederzeit später sein) Darüber hinaus wartet jede neue Client-Verbindung nur darauf, dass das Akzeptieren (oder eventuell das Timeout) aufgerufen wird. Sie können bis zu 50 Verbindungen haben, die standardmäßig auf die Annahme warten.

Wenn isOn == false, wartet Ihr Thread mit einer CPU. Ich schlage vor, dass Sie eine kleine Verzögerung wie Thread.sleep (250) einfügen. Dies wird die CPU drastisch reduzieren, aber nicht zu lange wieder starten.

BTW:

  • wenn Sie eine Ausnahme erhalten, sollten Sie es log/ausdrucken. Andernfalls, wenn es scheitert, wirst du nicht wissen warum.
  • Wenn das Akzeptieren fehlschlägt, kann es sein, dass der Prozess keine Dateien mehr enthält. Sie möchten also nicht, dass er einfach abstirbt und alle bestehenden Verbindungen löscht.
+0

Ich stimme völlig mit dem überein, was Sie gesagt haben. Außerdem haben Sie recht, wenn Sie das Flag auf "false" setzen, um sicherzustellen, dass ein anderes "auf eine Verbindung wartet", bevor der Server tatsächlich "nicht mehr bedient". Aber das erklärt immer noch nicht das unberechenbare Verhalten, das ich mit der aktuellen Version des Codes bekomme! Ich werde wahrscheinlich Ihre Lösung übernehmen, aber ich bin immer noch kurios, warum eine Version funktioniert und die andere nicht ... wenn logisch beide sollten. Die Frage war nicht wirklich, ob es eine bessere Lösung gibt (du hast es bereits bewiesen!), Aber warum verhält sich dieser Java-Code so unbeholfen? – Tibbers

+0

@Tibi, while (true) if (flag) und while (true) while (flag) sollte in Ihrem Fall identisch sein. Ich vermute, dass Ihr Test nicht stabil reproduzierbar ist. –

+0

Auch hier könntest du recht haben. Denn wenn ich die if-Variante mit dem Debugger starte und den Code Zeile für Zeile ausfühle funktioniert es einwandfrei ... aber wenn ich nur auf run klicke und es in Ruhe lasse funktioniert die if-Variante nicht! In der Tat kann ich den tatsächlichen Zustand der Maschine wahrscheinlich nicht reproduzieren, was jeden Versuch, dieses unbeholfene Verhalten zu verstehen, nutzlos macht. Wie auch immer, danke für die schnellen Antworten ... Ihr (erstes) Refactoring/Redesign-Angebot wurde bereits umgesetzt und wirkt wie ein Zauber! – Tibbers

0

Wenn Sie die while (true) und dann (this.isOn) while-Schleife hat keine Möglichkeit zu stoppen. Was passiert, wenn das isOn-Flag auf false gesetzt wird? Die while-Schleife hört nie auf, weil sie im Wesentlichen unendlich ist. Schließen Sie eine else-Anweisung an, um sie zu unterbrechen, und sie sollte wie erwartet funktionieren.

Wenn Sie die if-Anweisung herausnehmen und einfach while machen (this.isOn), dann endet die Schleife, wenn das isOn-Flag auf false gesetzt wird. Keine Endlosschleife.

Das sind meine Gedanken auf den ersten Blick ...

+0

Hallo! Hast du meinen P. S. gelesen? Wenn ich sage drehen Sie das if in eine Weile ich meine >>>> während (wahr) während (this.isOn) {...} << und es funktioniert so ... wie in der Verbindung ist erfolgreich etabliert! – Tibbers

+0

er möchte nicht aus der Schleife austreten, nur um die Weile drehen (wahr) warten auf das wenn es wahr werden soll. Das unerwartete Verhalten ist, dass wenn (isOn) niemals wahr wird und also kein Versuch unternommen wird,() zu akzeptieren, sondern stattdessen while (isOn) es tut. – djna

+0

Sie sind teilweise korrekt djna. Der Debugger in Eclipse sagt, dass die Flagge tatsächlich wahr wird. Und irgendwann sendet dieser neue Handler zum Thread-Pool. Aber aus irgendeinem Grund funktioniert es nicht. Aber wenn ich das ändere, wenn es in einer Weile wunderbar funktioniert (ohne irgendwelche anderen Änderungen irgendwo im Code)! – Tibbers

0

Meine Vermutung wäre auf Ihrer engen Schleife dort basieren. Ist es möglich, dass mehrere Instanzen des Programms auf Ihrem Server ausgeführt werden? Die if (isOn) -Version wird nicht heruntergefahren, wenn Sie isOn auf false setzen, stattdessen wird sie einfach für immer zum Brennen Ihrer CPU laufen.