Threads: Como saber que todas as threads já terminaram

4 respostas
renatoes

Boa tarde,

Fiz uma aplicação teste, que cria 20 threads e escrevem um valor em um arquivo.

...
        app.shutdown();
        try{
            boolean shutdown = false;
            while(!shutdown){
                if(app.isTerminated()) shutdown = true;
            }
            fileWriter.close();
        }catch(Exception e){
          e.printStackTrace();
        }

O objeto app é um ExecutorService. Pelo que li na API da classe, invocar o método shutdown inicia a finalização das threads, mas não necessariamente as finaliza. Como vocês podem notar, fiz um while que indicasse, através do métod isTerminated (este sim indica que as threads foram finalizadas), a finalização das threads. Minha dúvida é se existe alguma forma de sinalizar a finalização, uma vez que preciso fechar o stream do arquivo (criado pelo objeto FileWriter).

Agradeço desde já,

4 Respostas

ViniGodoy

Uma das assinaturas do ExecutorsService recebe um Future. O método get() do Future espera a thread terminar.
Sugiro que ao invés de implementar Runnable, você implemente um Callable<Boolean> e retorne true quando a thread terminou. Depois, para testar se todas as threads terminaram, basta fazer um for entre todos os futures chamando o método get().

Essa é uma maneira fácil de testar. Outra seria dar um join em cada uma das threads disparadas. Você também pode usar um barrier ou um ExecutionCompletionService.

ViniGodoy

Veja também: http://www.guj.com.br/posts/list/50321.java#264645

renatoes

Valeu Vini :smiley:
Vou fazer as alterações aqui

renatoes

Vou postar o código, creio que facilitará a explicação do Vini

/*
 * SynchronizedContador.java
 *
 * Criado em 3 de Dezembro de 2007, 10:16
 *
 * Propósito: Implementar um contador sincronizado.
 */

package desafio3;

/**
 * @author Renato
 */
public class SynchronizedContador {
   
    //Contador da classe
    private int contador = 0;
    
    /**
     * Incrementa o contador, e retorna seu valor atual
     * @return contador, se o seu valor for diferente de 101 
     *         -1, se o valor for igual a 101 (flag de estouro do contador)
     */
    public synchronized int incrementa(){
        if(contador == 101) return -1;
        return contador++;
    }
}
/*
 * SynchronizedContador.java
 *
 * Criado em 3 de Dezembro de 2007, 10:16
 *
 * Propósito: Implementar a classe utiliza pelas threads para recuperar o valor do contador
 * e escrever no arquivo.
 */

package desafio3;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * @author Renato
 */
public class ThreadContadora implements Callable<Boolean>{
    
    //Condição de suspensão da thread
    private Condition suspensao;
    //Indica se a thread está suspensa
    private boolean suspenso;
    //Lock compartilhado para bloquear o acesso de outras threads (o que causaria InterruptedException)
    private Lock lock;
    //Contador compartilhado das threads
    private SynchronizedContador contador;
    //FileWriter compartilhado das threads
    private FileWriter fileWriter;
    //Nome de cada thread
    private String nome;
    
    /**
     * Construtor da classe ThreadContadora
     * @param nome - nome da thread
     *        fileWriter - objeto FileWriter compartilhado pelas threads
     *        lock - objeto Lock compartilhado pelas threads
     *        contador - objeto SynchronizedContador compartilhado pelas threads
     */
    public ThreadContadora(String nome, FileWriter fileWriter, Lock lock, SynchronizedContador contador){
      
        this.nome = nome;
        this.lock = lock;
        this.contador = contador;
        this.fileWriter = fileWriter;
    }
    
    /**
     * Overload do método call, chamado na execução das threads
     */
    public Boolean call() throws Exception {
        
        int c = contador.incrementa();
       
        while(c != -1){
            
            //Loop de permissão para escrever no arquivo e ler o valor do contador
            try{
                Thread.sleep(1000);
                lock.lock();
                try{
                    while(suspenso) suspensao.await();
                }finally{
                    lock.unlock();
                }
            }catch(InterruptedException e){
                e.printStackTrace();
            }finally{
                try {
                    fileWriter.write(String.format("%s: count = %d\n",nome,c));
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
                c = contador.incrementa();
            }
            
            }
            return true;
    }
 }
/*
 * Main.java
 *
 * Criado em 3 de Dezembro de 2007, 10:16
 *
 * Propósito: Inicializar a aplicação
 */

package desafio3;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.Future;

/**
 * @author Renato
 */
public class Main {
    
    public static void main(String[] args){
        
        //Inicializa os objetos compartilhados
        SynchronizedContador contador = new SynchronizedContador();
        Lock lock = new ReentrantLock(true);
        FileWriter fileWriter = null;
        
        try {
            fileWriter = new FileWriter(new File("teste.txt"), true);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        
        //Inicializa o executor de threads e as threads
        ExecutorService app = Executors.newFixedThreadPool(10);
        
        ThreadContadora thread1 = new ThreadContadora("Thread1",fileWriter, lock,contador);
        ThreadContadora thread2 = new ThreadContadora("Thread2",fileWriter, lock,contador);
        ThreadContadora thread3 = new ThreadContadora("Thread3",fileWriter, lock,contador);
        ThreadContadora thread4 = new ThreadContadora("Thread4",fileWriter, lock,contador);
        ThreadContadora thread5 = new ThreadContadora("Thread5",fileWriter, lock,contador);
        ThreadContadora thread6 = new ThreadContadora("Thread6",fileWriter, lock,contador);
        ThreadContadora thread7 = new ThreadContadora("Thread7",fileWriter, lock,contador);
        ThreadContadora thread8 = new ThreadContadora("Thread8",fileWriter, lock,contador);
        ThreadContadora thread9 = new ThreadContadora("Thread9",fileWriter, lock,contador);
        ThreadContadora thread10  = new ThreadContadora("Thread10",fileWriter, lock,contador);
       
        //Executa as threads, e armazena o resultado da finalização da thread
        ArrayList<Future<Boolean>> resultados = new ArrayList<Future<Boolean>>();
        
        try{
            resultados.add(app.submit(thread1));
            resultados.add(app.submit(thread2));
            resultados.add(app.submit(thread3));
            resultados.add(app.submit(thread4));
            resultados.add(app.submit(thread5));
            resultados.add(app.submit(thread6));
            resultados.add(app.submit(thread7));
            resultados.add(app.submit(thread8));
            resultados.add(app.submit(thread9));
            resultados.add(app.submit(thread10));
        }catch( Exception e){
            e.printStackTrace();
        }
        
        
        //Utiliza o método Future.get para determinar a finalização das threads
        for(Future<Boolean> f: resultados){
            try {
                if(f.get() == true);
            } catch (ExecutionException ex) {
                ex.printStackTrace();
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
        
        //Fecha o executor e o FileWriter
        app.shutdown();
        try{
            fileWriter.close();
        }catch(Exception e){
            e.printStackTrace();
        }
            
    }
        
}

Qualquer outra sugestão por favor repassem no fórum
[]'s

Criado 3 de dezembro de 2007
Ultima resposta 3 de dez. de 2007
Respostas 4
Participantes 2