O seu problema basicamente é conceitual.
É que ensinam a mexer com threads em vez de pensar em nível mais abstrato (mas que é mais concreto para as pessoas) - tarefas e executores.
O resultado líquido é que você começa a ver programas com threads que têm um monte de “sleep”, "wait " e “notify” e “setPriority” que funcionam apenas por milagre (se é que funcionam). Em particular, se um programa precisa de um “setPriority” para aparentemente funcionar, provavelmente ele está errado.
Um “executor” é algo que lida com “tarefas” e pode executá-las em paralelo com outros “executores”.
Pense num “executor” como se fosse um caixa de supermercado, e uma “tarefa” como sendo um cliente que está esperando ser atendido,
Um “executor” pode ser implementado como se fosse uma thread, ou então de outra maneira. Pode ser até implementado como um conjunto de threads, por exemplo.
No seu caso, você precisa ter o conceito de “produtor” (aquele que gera as tarefas) e “consumidor” (aquele que executa as tarefas).
Em seu lugar, eu faria algo como:
/**
*
*/
package guj;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* Este exemplo cria um ExecutorService que é um pool de threads que irão atender aos pedidos.
* Tempo de simulação: 1 minuto
* Tempo em que cada thread atende a um pedido: entre 1.5 e 2.5 segundos (distribuição uniforme)
* Quantidade de threads: 3
* Quantidade de pedidos: 100
*/
public class ExemploProdutorConsumidores {
/**
* @param args
*/
public static void main(String[] args) throws InterruptedException {
ExecutorService es = Executors.newFixedThreadPool(3);
final Random r = new Random();
for (int i = 0; i < 100; ++i) {
final int cnt = i;
es.execute(new Runnable() {
@Override
public void run() {
// Atendimento do pedido por uma das threads do pool de threads
// Note que o número da thread pode ser *8", "9" ou "10" porque qualquer programa Java,
// por mais simples que seja, já tem cerca de 6 a 7 threads, que são usadas
// pela JVM para seus propósitos.
System.out.printf ("Pedido %d será atendido pela thread %d %n", cnt, Thread.currentThread().getId());
long t = System.currentTimeMillis(); // Thread.sleep simula um processo lento
try { Thread.sleep (1500 + r.nextInt(1000)); } catch (InterruptedException ex) { }
System.out.printf ("Pedido %d atendido em %d ms %n", cnt, System.currentTimeMillis() - t);
}
});
}
es.awaitTermination(60, TimeUnit.SECONDS);
}
}