3 Stimmen

Wie kann ich eine Funktion, die in Java blockiert, zeitlich begrenzen?

Im Grunde rufe ich BufferedReader.ReadLine(); Ich bin jedoch in einem Multithreading-Server, wo ich einen Knoten in einem Baum synchronisiere. Also, wenn diese ReadLine-Funktion aufgerufen wird, wenn jemand anderes den Knoten erreicht, sind sie ausgesperrt. Ich kann nicht herausfinden, wie ich ein Zeitlimit für die Zeit setzen kann, die ReadLine auf eine Antwort wartet, bevor der Thread beendet wird. Das Naheliegendste war, einen neuen Thread zu erstellen, der für 1 ms schläft und dann prüft, ob die Variable, auf die ich ReadLine gesetzt habe, geändert wurde. Also etwas wie dies:

synchronized (pointer) {
    String answer = "";
    Thread d = new Thread(new Runnable() {
        public void run() {
            try {
                int i = 0;
                while (answer.equals("")) {
                    if (i == 10000) {
                        System.out.println("Timeout Occured");
                        System.exit(0);
                    }
                    try {
                        Thread.sleep(1);
                        i++;
                    }
                    catch(Exception e) {
                        System.out.println("sleep problem occured");
                    }
                }
            }
            catch (IOException ex) {
            }
        }    
    });

    d.start();
    answer = socketIn.readLine();
}

Das tat, was ich wollte, aber ich konnte nicht herausfinden, wie ich den aktuellen Thread stoppen konnte, um den Knoten zu entsperren, damit andere Benutzer weitermachen konnten, anstatt den gesamten Server abzuschalten. Schließlich dachte ich, vielleicht könnte ich dies tun:

    Thread d = new Thread(new Runnable() {
        public void run() {
            try {
                answer = socketIn.readLine(); 
            } catch (IOException ex) {
            }
        }    
    });

    d.join(10000);
    catch (InterruptedException e){
    socketOut.println("Timeout Occured. Returning you to the beginning...");
    socketOut.flush();
    return;
}

Aber das scheint immer noch zu blockieren und nicht in der Lage zu sein, fortzufahren. Kann mir jemand dabei helfen? Ich kann nicht verstehen, was ich falsch mache?

Ich habe auch versucht, den ExecutorService zum Laufen zu bringen, aber das ist mir nicht gelungen. Ist das meine Antwort? Wie würde ich es implementieren?

[EDIT] socketIn ist ein BufferedReader, sollte gesagt haben, dass explizit sorry. Außerdem verbindet sich der Client über Telnet, obwohl ich nicht glaube, dass das eine Rolle spielt.

Was ich hier tue, ist ein "Prominenten-Ratespiel", bei dem Benutzer Prominente zum Baum hinzufügen können. Daher muss ich den Knoten, den die Person bearbeitet, aus Gründen der Thread-Sicherheit sperren

3voto

Brian Roach Punkte 74523

Ist das eine Hausaufgabe? Sie ist verdächtig nah an einer Frage, die gestern von jemand anderem gestellt wurde. Wenn ja, sollte sie als Hausaufgabe gekennzeichnet sein.

Sie müssen nur etwas sperren, wenn ein Thread Daten ändert, die andere Threads lesen/ändern können.

Wenn Sie etwas sperren, das auf eine Eingabe wartet, ist der Anwendungsbereich Ihrer Sperre viel zu breit.

Ihr Fluss sollte sein:

  • Eingabe vom Client lesen (blockiert readLine())
  • gemeinsame Ressource sperren
  • ändern.
  • freischalten

(Dies ist vorausgesetzt, Sie haben einen Thread pro Verbindung/Client, und sind auf das Lesen vom Client blockiert)

Davon abgesehen ... wenn Sie aus einem Socket lesen und wollen, dass es zu einem Timeout kommt, müssen Sie clientSocket.setSoTimeout(1000); wenn Sie die Verbindung zum ersten Mal annehmen. Wenn Ihr BufferedReader auf diese Zeitspanne (in Millisekunden) wartet und keine Eingabe erhält, wird ein java.net.SocketTimeoutException

String inputLine = null;
try 
{
    inputLine = in.readLine();
    if (inputLine == null)
    {
        System.out.println("Client Disconnected!");
    }
    else 
    {
        // I have input, do something with it
    }
}
catch(java.net.SocketTimeoutException e)
{
    System.out.println("Timed out trying to read from socket");
}

1voto

Alles ist bereits erledigt. Versuchen Sie zu verwenden java.util.concurrent .

    //
    // 1. construct reading task
    //
    final FutureTask<String> readLine = new FutureTask<String> (
        new Callable<String>() {
            @Override public String call() throws Exception {
                return socketIn.readLine();
            }
        }
    );
    //
    // 2. wrap it with "timed logic"
    //    *** remember: you expose to your users only this task
    //
    final FutureTask<String> timedReadLine = new FutureTask<String> (
        new Callable<String>() {
            @Override public String call() throws Exception {
                try {
                    //
                    // you give reading task a time budget:
                    //      try to get a result for not more than 1 minute
                    //
                    return readLine.get( 1, TimeUnit.MINUTES );
                } finally {
                    //
                    // regardless of the result you MUST interrupt readLine task
                    // otherwise it might run forever
                    //      *** if it is already done nothing bad will happen 
                    //
                    readLine.cancel( true );
                }
            }
        }
    )
    {
        //
        // you may even protect this task from being accidentally interrupted by your users:
        //      in fact it is not their responsibility
        //
        @Override
        public boolean cancel(boolean mayInterruptIfRunning) {
            return false;
        }
    };

    Executor executor = Executors.newCachedThreadPool();

    // 3. execute both
    executor.execute( readLine );
    executor.execute( timedReadLine );

    // 4. ...and here comes one of your users who can wait for only a second
    try {
        String answer = timedReadLine.get(1, TimeUnit.SECONDS);
        //
        // finally user got his (her) answer
        //
    } catch (InterruptedException e) {
        //
        // someone interrupted this thread while it was blocked in timedReadLine.get(1, TimeUnit.SECONDS)
        //
    } catch (ExecutionException e) {
         //
        // e.getCause() probably is an instance of IOException due to I/O failure
        //
    } catch (TimeoutException e) {
        //
        // it wasn't possible to accomplish socketIn.readLine() in 1 second
        //
    }

0voto

Jeff Punkte 31

Ich habe eine Lösung gefunden:

answer = "";
try{
    Thread d = new Thread(new Runnable() {
        public void run() {
            try {
                answer = socketIn.readLine();
            }   
            catch (IOException ex) {
                System.out.println("IO exception occurred");
            }
        }
    });
    d.join(10000); //Not sure if this is superfluous or not, but it didn't seem to work without it.
    d.start();
    i = 0;
    while (true){
        if (i == 10000){
            if (d.isAlive()) throw InterruptedException;
        }
        if (answer.equals("")){
            Thread.sleep(1);
        }
        else{
            break;
        }
        i++;
    }
    //This essentially acts as Thread.sleep(10000), but the way I 
    //implemented it, it checks to see if answer is modified or not every  
    //.001 seconds. It will run for just over 10 seconds because of these checks. 
    //The number in Thread.sleep could probably be higher, as it is 
    //unnecessary to check so frequently and it will make the code more efficient
    //Once it hits 10000, it throws an exception to move to the catch block below
    //where the catch block returns everything to its original state and 
    //returns the client to the beginning
    }
catch (Exception e){
    socketOut.println("Timeout Occurred. Returning you to the beginning...");
    socketOut.flush();
    pointer = tree.root;
    //reset class members to their original state
    return;
}

Danke, dass Sie es sich angesehen haben, Brian Roach. Ihr Beitrag war informativ, aber ich habe versehentlich einige wichtige Informationen ausgelassen. Ich werde versuchen, in Zukunft sorgfältiger zu sein.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X