Naturalmente, a primeira coisa com que comecei foi Habr. Mas, infelizmente, encontrei apenas dois artigos aqui:
habrahabr.ru/post/260953
habrahabr.ru/post/116363
O primeiro, obviamente, para quem entende e tem experiência com ExecutorService. O segundo, infelizmente, não entrou em mim. Parece pequeno e "no caso", mas depois de reler várias vezes ainda não entendi o que ExecutorService é e com o que se come. Então eu tive que sentar no Eclipse,
Então, vamos dar uma olhada em um exemplo simples:
ExecutorService service = Executors.newFixedThreadPool(3);
service.execute(new Runnable() {
public void run() {
System.out.println("Another thread was executed");
}
});
Neste exemplo, criamos o próprio objeto ExecutorService e chamamos o método execute nele. Passando a implementação de thread mais comum para ele. Tudo isso poderia ter sido construído à maneira do velho avô, mas isso, você vê, é muito mais simples e mais elegante. Na verdade, nós rapidamente ramificamos outro encadeamento assíncrono do encadeamento atual, que pode fazer algo lá em segundo plano.
Criamos o objeto ExecutorService usando uma fábrica. Seus métodos são bastante óbvios, por isso não vamos procrastinar muito. Aqui estão alguns deles:
ExecutorService service1 = Executors.newSingleThreadExecutor();
ExecutorService service2 = Executors.newFixedThreadPool(3);
ExecutorService service3 = Executors.newScheduledThreadPool(3);
Além do método execute, que é chamado de acordo com o princípio "dispare e esqueça", nosso serviço também possui um método submit. A única diferença do primeiro é que o último retorna um objeto da interface Future. Essa é uma ótima maneira de controlar o estado do thread que executamos em segundo plano. É feito algo assim:
Future future = service.submit(new Runnable() {
public void run() {
System.out.println("Another thread was executed");
}
});
...
future.get();
Observe que o método get bloqueará mortalmente o thread atual e esperará até que o thread em segundo plano termine. Agora você não precisa de todas essas junções não óbvias! Se tivermos medo de que nosso thread em segundo plano nunca termine, podemos usar get (long, TimeUnit).
Às vezes, você precisa retornar dados de um thread de segundo plano para o atual. O método submit também nos ajudará com isso, mas agora precisamos passar para ele não um objeto Runnable, mas um objeto Callable. Na verdade, são duas interfaces idênticas, a única diferença é que a última pode retornar algo:
Future future = service.submit(new Callable(){
public Object call() throws Exception {
System.out.println("Another thread was executed");
return "result";
}
});
...
System.out.println("Result: " + future.get());
Bem, em resumo, isso é tudo. Eram métodos de criação de ExecutorService - e na fábrica (que são muitos), eram os métodos de ExecutorService, problemas de tratamento de erros em um thread de segundo plano, mas isso é outra história ...
No final de não se esqueça de:
servcie.shutdown();
Ou não, se todos os threads de fundo forem daemons.