Ola pessoal,
Fiz um programa que lê linha a linha de arquivos de um diretório e insere os dados no banco de dados, tudo bem até aqui.
Mas eu tenho vários arquivos para processar, ~19k arquivos, então eu quero ler vários arquivos ao mesmo tempo, com uma tarefa pra cada.
Procurei sobre ThreadPoolExecutor mas não achei muita coisa pra me ajudar, sem contar que não entendo muito de thread…
E então,
Como posso fazer pra ler vários arquivos ao mesmo tempo, um por tarefa, e sem perigo de uma thread tentar ler um arquivo que já está sendo lido?
Divida a lista de arquivos em n-listas, sendo que n é o número de threads que serão executadas. Assim você evita que mais de uma thread acesse o mesmo arquivo ao mesmo tempo, sem precisar usar sincronização. Daí, é só inicializar a classe que executa o processamento e iniciar as threas.
Agora, tem alguns pontos a considerar :
-
número de threads: ao dividir o programa em threads, você somente vai ter algum ganho se você de fato puder paralelizar a tarefa, isso é, se você estiver em um ambiente multiprocessado, de forma que você tenha uma thread para cada processador.
-
gargalo: você tem que identificar também qual é o gargalo, se é o tempo de CPU ou a leitura/escita de arquivos. Se o garganlo é a CPU, ok, você vai ter ganhos em paralelizar a tarefa. Porém, se o gargalo for a leitura/escrita dos arquivos o ganho não é tão grande, e é provável que você tenha que recorrer a recursos como non-blocking I/O.
Bom, mas como fazer isso?
Array de Thread? TheadPoolExecutor?
Não faço muita idéia de como começar, estou perdido 
Tem como mostrar algum exemplo?
Vou ter um array de arquivos,
quero ter no máximo 20 threads, uma por arquivo,
e assim que liberar uma thread, inicia outra com outro arquivo.
É bem isso que quero fazer, mas não sei bem como começar
Não entendi. Se você quer processar os arquivos sequencialmente, porque você quer usar threads ? Nesse caso é só chamar um método em loop.
De qualquer maneira, tente começar com a solução sequencial, teste o desempenho dela antes pra saber se realmente compensa paralelizar a tarefa.
Já estou chamando o método de carga em loop.
Só que tenho a seguinte situação:
Tenho vários arquivos de tamanhos diferentes e
alguns arquivos demoram quase 1 hora para carregar.
Nesse meio tempo eu pretendo ter outras threads processando outros arquivos.
Já tenho a solução sequencial, eu já testei o programa rodando várias vezes,
só que cada um lendo de um diretório diferente, mas isso não é legal no meu caso.
Eu tenho que ler todos os arquivos do mesmo diretório, porque o programa vai ficar rodando,
enquanto chega mais e mais arquivos.
Bom, nesse caso eu começaria de uma maneira simples. O processamento do arquivo eu isolaria em uma classe Runnable, mais ou menos assim:
class FileProcessor implements Runnable{
private File fileToProcess;
public FileProcessor(File fileToProcess){
this.fileToProcess = fileToProcess;
}
public void run(){
processFile();
}
public void processFile(){
//aqui vem o processamento do seu arquivo
}
}
E para o disparo das threads eu usaria um executor:
int janelaProcessamento = 4; //4 CPU's
ScheduledExecutorService executor = Executors.newScheduledThreadPool(janelaProcessamento);
for(File f : listaArquivos){
executor.execute(new FileProcessor(f)) ;
}
executor.awaitTermination(0 , TimeUtils.SECONDS); //acho que assim o timeout é ilimitado
Me explica esse segundo código, por favor.
4 é o número de janelaProcessamento, blz.
Ao percorrer o array de arquivos, vou executando o FileProcessor;
Só que, se eu tiver mais arquivos que o número de processamento?
o executor vai ficar aguardando terminar para passar para o próximo arquivo?
Não necessariamente. O que você está fazendo é pedindo para o executor criar uma thread na fila de execução. O momento exato em que a thread ganha a CPU depende do algoritmo de escalonamento da JVM e do SO, e ainda, do estado da máquina, se existe operações de I/O, etc.
Mas uma correção nesse meu código: o pool de threads do executor pode ser até um pouco maior que o número de processadores. Isso porque eu não tinha pensado que quando uma thread for bloqueada para I/O o executor pode escalonar mais uma thread, e ficar com a fila de execução maior do que o número de processadores.
De qualquer maneira, o caminho das pedras já foi dado. Você tem que implementar e testar.
Consegui implementar, ficou uma beleza. 
como funciona o método awaitTermination() ?
Defini o tempo pra 10 segundos, pra testar, mas esse tempo é o que ele aguarda pra terminar a thread quando não tem mais arquivos?
Não, esse é o timeout das tarefas. Se as threas não terminarem dento desse tempo o executor é finalizado. Esse método serve para bloquear a thread atual, aguardando que as threads restantes terminem sua execução.
Cara, você já achou o caminho das pedras, que é o mais importante. Esse tipo de informação você pode achar na documentação do Java, que é bem completa, crie esse hábito, caso contrário você nunca vai conseguir andar com as próprias pernas.
Tudo bem, muito obrigado por ter me ajudado até aqui. 
Eu leio a documentação sim, só que, parti pro Java a pouco tempo,
então ainda estou me habituando a documentação.
Valeu,
esse tópico está resolvido até então.