Toon posts:

[JAVA] thread stoppen

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik heb een agent-based applicatie die aangestuurd wordt via een GUI. De agents extenden allemaal van Thread en in die agenten zitten weer eigen threads met communicatie classes. Nu start ik de agents vanuit de gui door op de knop run te drukken. Dan gebeurt hetvolgende:

code:
1
2
3
4
5
6
7
Agent agent1 = new Agent();
agent1.start();

...

Agent agentn = new Agent();
agentn.start();


Nu heb ik ook een knop quit. Als er op deze knop gedrukt wordt, zou ik de agenten willen stoppen. maar als ik agent1.interrupt() aanroep, blijft de agent gewoon doorwerken.
Wat moet ik doen om de agent te stoppen? Google geeft me alleen tutorials terug, maar weinig informatie over classes die Threads extenden.

  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

Threads moet je eigenlijk niet willen onderbreken, zoals je waarschijnlijk al uit de tutorials begrepen hebt, omdat je zelden weet of dat veilig kan. Je kan zo'n agent op een bepaalde conditie laten wachten, die hij periodiek checked.
Java:
1
2
3
4
while (!threadShouldFinish) {
   // do interesting stuff relative to which the amount of sleep is acceptable
   Thread.sleep(SLEEP_TIME_IN_MS);
}

waarbij je threadShouldFinish van buitenaf zet. Dan kan je daarna nog wat opruimwerk laten doen. Wel genoeg wachttijd nemen, anders vreet je thread alle processorcapaciteit op.

Maar dit is zelden de netste, beste oplossing voor een probleem. Het klinkt alsof de Runnable interface en java.util.concurrent.ThreadPoolExecutor weleens je vrienden zouden kunnen worden.

[ Voor 3% gewijzigd door Confusion op 21-03-2007 22:18 ]

Wie trösten wir uns, die Mörder aller Mörder?


  • den 150
  • Registratie: Oktober 2002
  • Niet online
Interrupt is eigenlijk de manier om threads te stoppen. (Blijf aub weg van Thread.stop)
Een deel van de java api's luistert op interrupts en gooit dan een interrupted exception. Dit is hetzelfde principe dat Confusion uitlegt: checken op een flag en daarop reageren. Als die interrupted exception wordt gegooid kan je die catchen en resources releasen.

Als je geen enkele java api gebruikt die InterruptedExceptions gooit dan moet je zelf op interrupted checken. Ik weet dat je dan zelf de interrupted status moet clearen,maar de details zoek je best even op.

Java IO is spijtig genoeg niet interrupt() friendly. Het enige wat helpt is de onderliggende stream closen als je bvb op network input wacht.

Aangezien je Thread extends ipv Runnable implementeert neem ik aan dat je weinig ervaring hebt met threads. Java threads zijn relatief eenvoudig, maar concurrency is a bitch >:) . Ik kan je dit boek dan ook ten zeerste aanraden

Verwijderd

Ja en die vlag is eigenlijk 'Thread.currentThread().isInterrupted()'. Maar zoals vermeld: er komt veel meer bij kijken.

Verwijderd

Topicstarter
Ja, eingelijk had ik al zo een constructie in de main loop... Alleen een duuwtje in de richting nodig om het goed op te lossen.
Blijf ik nog zitten met het volgende:

Alle agents hebben een serversocket waarlangs berichten binnenkomen. Als de socket accept doet, dan wordt in een nieuwe thread (class implements runnable) afgevangen. het bericht wordt gelezen en de socket wordt gesloten. Nu wil ik dat, als de agent uit zijn main loop gaat, ook de serversocket stoppen. Op die mannier kan ik (zonder de applicatie te herstarten) de agent herstarten. Maar de serversocket vindt het blijkbaar niet zo een goed idee om gestopt te worden. Ik heb geprobeerd om de socket te sluiten na de main loop (die op dezelfde mannier breekt als die van de agents) en in een finalize methode. Geen van beiden schenen echter te werken... Hoe kan ik deze het beste stoppen?

  • MTWZZ
  • Registratie: Mei 2000
  • Laatst online: 13-08-2021

MTWZZ

One life, live it!

Als ik je goed begrijp heb je deze situatie:
code:
1
2
3
4
5
6
Main applicatie
 - Agent (met socket A)
 - - Accept -> runnable klasse (met client socket)
 - - Accept -> runnable klasse (met client socket)
 - Agent (met socket B)
 - Agent (met socket C)

En je wil bijvoorbeeld de 2e Agent (met socket B ) stoppen?

Volgens mij moet je dan zoiets doen: (pseudo code)
Java:
1
2
3
4
5
6
7
8
9
10
11
void StartAgentLoop {
    // blijf in de loop
    loop(!stoppenMetLoop) {
        Socket client = serverSocket.Accept();

        AcceptKlasse.Start(client);
    }

    // klaar met loop
    serverSocket.Close();
}

Wel behoorlijk basic maar redelijk recht-toe recht-aan.

Nu met Land Rover Series 3 en Defender 90


  • Zyppora
  • Registratie: December 2005
  • Laatst online: 28-11 08:48

Zyppora

155/50 Warlock

Ik denk dat je probleem is dat accept() blokkeert (en to be honest weet ik niet of je dat kunt veranderen in Java). Een workaround zou kunnen zijn om bij het 'afsluiten' een dummy socket te laten connecten, zodat er door de accept() gelopen wordt, en deze meteen weer netjes afsluiten (en met de loop van Confusion ervoor zorgen dat de accept() niet opnieuw aangeroepen wordt). Een beetje omslachtig, maar het werkt wel.

[ Voor 6% gewijzigd door Zyppora op 22-03-2007 12:19 ]

Phenom II X4 945 \\ 8GB DDR3 \\ Crosshair IV Formula \\ R9 290


  • Marcj
  • Registratie: November 2000
  • Laatst online: 10:21
Dat kun je beter oplossen door een timeout te setten voor de serversocket met setSoTimeout(). Dan gooit de accept() functie om de zoveel milliseconden een SocketTimeoutException (wanneer er dus langer dan een aantal milliseconden niets geconnect is).

edit: Zoiets dus...
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void acceptConnections() {
  serverSocket.setSoTimeout(1000); // Set een timeout van 1 seconde
  try {
    while(!done) {
      try {
        Socket s = serverSocket.accept();
      } catch(SocketTimoutException ex) {
        // Normale timeout, ga verder...
      }
    }
  } catch(IOException ex) {
    //Doe iets met de andere excepties
  } finally {
    serverSocket.close();
  }
}

[ Voor 39% gewijzigd door Marcj op 22-03-2007 12:30 ]


  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

Verwijderd schreef op donderdag 22 maart 2007 @ 11:56:
Ik heb geprobeerd om de socket te sluiten na de main loop (die op dezelfde mannier breekt als die van de agents) en in een finalize methode.
Op finalize kan je nauwelijks / niet vertrouwen. Je weet namelijk niet wanneer die methode aangeroepen zal worden.

Wie trösten wir uns, die Mörder aller Mörder?


  • Janoz
  • Registratie: Oktober 2000
  • Nu online

Janoz

Moderator Devschuur®

!litemod

Ikzelf heb een inimini webservertje gemaakt in java zodat ik makkelijk een webinterface kan hangen aan mijn applicatie. De hoofdlus die binnengekomen requests accepteerd heb ik een daemonthread gemaakt. Deze thread blijft lopen zolang de rest van de applicatie ook nog loopt. Bij het sluiten van de applicatie wordt niet op het stopen van deze thread gewacht. Zeker voor een thread die alleen maar naar een inkomende verbinding loopt te luisteren lijkt me dat geen enkel probleem.

edit: Stukie code:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    public void start() throws IOException{
        try {
            final ServerSocket ss = new ServerSocket(port);
            Thread t = new Thread(new Runnable() {
                public void run() {
                    try {
                        while (true)
                            new Httpd.RequestProcessor(ss.accept(),handler,serverName);
                    } catch (IOException e) {
                        System.err.println("Error accepting requests");
                    }
                }
            });
            t.setDaemon(true);
            t.start();
        } catch (IOException e) {
            System.err.println("Error accepting requests");
            throw e;
        }
    }

[ Voor 37% gewijzigd door Janoz op 22-03-2007 13:26 ]

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Verwijderd

Topicstarter
Marcj schreef op donderdag 22 maart 2007 @ 12:27:
Dat kun je beter oplossen door een timeout te setten voor de serversocket met setSoTimeout(). Dan gooit de accept() functie om de zoveel milliseconden een SocketTimeoutException (wanneer er dus langer dan een aantal milliseconden niets geconnect is).

edit: Zoiets dus...
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void acceptConnections() {
  serverSocket.setSoTimeout(1000); // Set een timeout van 1 seconde
  try {
    while(!done) {
      try {
        Socket s = serverSocket.accept();
      } catch(SocketTimoutException ex) {
        // Normale timeout, ga verder...
      }
    }
  } catch(IOException ex) {
    //Doe iets met de andere excepties
  } finally {
    serverSocket.close();
  }
}
dit is em!!! bedankt marcj.
SOLVED
Pagina: 1