Como finalizar Thread com método blocante de I/O ?[RESOLVIDO]

Pessoal,

Tenho um pedaço de código assim, dentro de uma Thread:

while(ativo){
    String mensagem = reader.readLine();
}

public void parar(){
ativo = false;
}

Como faço para finalizar essa Thread ? O método readLine é blocante, e se chamar reader.close, trava a aplicação.

Obrigado

Acho que no seu caso, apenas o

System.exit(0);

resolveria, não?

Abs!

Nessa caso sairia do sistema… preciso finalizar a Thread.

Só há uma maneira.

Interrompe a thread com interrupt e dá um join nela para esperar ela morrer.

Agora se ela estiver bloqueada em alguma coisa não interrompível (loop infinito / busy spinning) aí impossível…

Acho que o readLine é interrompível… Então primeiro seta ativo pra false e manda um thread.interrupt();

readline() tem um tem um for assim:

for(;;)

Então… lascou-se ?

[quote=turim]readline() tem um tem um for assim:

for(;;)

Então… lascou-se ?
[/quote]

Essa é a típica linha de comanda cretina. Não sei o que ela faz. Mas não acho que seja uma loop infinita.

Parece que o readLine não gosta de ser interrompida => http://stackoverflow.com/questions/3595926/how-to-interrupt-bufferedreaders-readline

Testa aí e depois posta aí o que vc concluiu.

acredito que seja um loop infinito sim, olha só o código:

 String readLine(boolean ignoreLF) throws IOException {
        StringBuffer s = null;
        int startChar;

        synchronized (lock) {
            ensureOpen();
            boolean omitLF = ignoreLF || skipLF;

        bufferLoop:
            for (;;) {

                if (nextChar >= nChars)
                    fill();
                if (nextChar >= nChars) { /* EOF */
                    if (s != null && s.length() > 0)
                        return s.toString();
                    else
                        return null;
                }
                boolean eol = false;
                char c = 0;
                int i;

                /* Skip a leftover '\n', if necessary */
                if (omitLF && (cb[nextChar] == '\n'))
                    nextChar++;
                skipLF = false;
                omitLF = false;

            charLoop:
                for (i = nextChar; i < nChars; i++) {
                    c = cb[i];
                    if ((c == '\n') || (c == '\r')) {
                        eol = true;
                        break charLoop;
                    }
                }

                startChar = nextChar;
                nextChar = i;

                if (eol) {
                    String str;
                    if (s == null) {
                        str = new String(cb, startChar, i - startChar);
                    } else {
                        s.append(cb, startChar, i - startChar);
                        str = s.toString();
                    }
                    nextChar++;
                    if (c == '\r') {
                        skipLF = true;
                    }
                    return str;
                }

                if (s == null)
                    s = new StringBuffer(defaultExpectedLineLength);
                s.append(cb, startChar, i - startChar);
            }
        }
    }

Tem que olhar o método fill(), que deve ser o que bloqueia… um thread geralmente é um loop infinito… o que ele precisa são break points (return ou break) ou pontos de interrupção… (que respondem ao interrupt() jogando uma InterruptedException)

método fill

    private void fill() throws IOException {
        int dst;
        if (markedChar <= UNMARKED) {
            /* No mark */
            dst = 0;
        } else {
            /* Marked */
            int delta = nextChar - markedChar;
            if (delta >= readAheadLimit) {
                /* Gone past read-ahead limit: Invalidate mark */
                markedChar = INVALIDATED;
                readAheadLimit = 0;
                dst = 0;
            } else {
                if (readAheadLimit <= cb.length) {
                    /* Shuffle in the current buffer */
                    System.arraycopy(cb, markedChar, cb, 0, delta);
                    markedChar = 0;
                    dst = delta;
                } else {
                    /* Reallocate buffer to accommodate read-ahead limit */
                    char ncb[] = new char[readAheadLimit];
                    System.arraycopy(cb, markedChar, ncb, 0, delta);
                    cb = ncb;
                    markedChar = 0;
                    dst = delta;
                }
                nextChar = nChars = delta;
            }
        }

        int n;
        do {
            n = in.read(cb, dst, cb.length - dst);
        } while (n == 0);
        if (n > 0) {
            nChars = dst + n;
            nextChar = dst;
        }
    }

Aí tem que ver se o método in.read( … ) pode ser interrompível…

Melhor simplesmente fazer um teste e chamar thread.interrupt() e ver se funciona… se não vc vai ficar procurando agulha em palheiro… pelo que escreveram lá no StackOverflow parece que não funciona não, o que é estranho…

public void parar() {
 ative = false;
 thread.interrupt();
System.out.println(thread.isAlive());
}

retornou true.

[quote=turim] public void parar() { ative = false; thread.interrupt(); System.out.println(thread.isAlive()); }

retornou true.[/quote]

Claro pois vc não deu thread.join(). interrupt() é assíncrono!

travou no join.

[quote=turim]travou no join.

[/quote]

Então a thread não está morrendo, tá ficando travada ad eterna. Naquele post do stack overflow o pessoal estava reclamando exatamente disso. Parece que para destravar o readLine só fechando o stream que ele está escutando OU mandar um EOF marker.

o estranho é que se chamar o método close() a aplicação trava.

Galera, só para compartilhar com vocês, resolvi o problema, não sei se é da forma correta.

Quando que parar de receber as mensagens, fecho a conexão com o servidor e seta a flag para false. Assim Quando o servidor detecta que a conexão com o cliente fachou, ele também fecha o fluxo, assim acontece uma Exception na Thread do cliente,
continuando o while, com a flag False ele finaliza a Thread.

Dessa forma cheguei a meu objetivo.

while (ativo) {
 try{
    String msg= reader.readLine();
}catch(Exception e){
    if(ativo){
    //notifica listener que ocorreu uma exceção
    }
}
}

public void finaliza(){
connection.close(); //Fecha conexão
ativo = false;//altera flag
}

Obrigado pelas dicas.

[]s

Cata a InterruptedException ao invés de Exception lá… É ela que diz se o thread foi interrompido após o fechamento da conexão. Vc não quer ignorar uma exception real aí.

Outra coisa que vc deve fazer é primeiro setar a flag e depois fechar.