SlideShare uma empresa Scribd logo
1 de 79
Baixar para ler offline
UNIVERSIDADE ESTADUAL DO SUDOESTE DA BAHIA
CURSO DE CIÊNCIA DA COMPUTAÇÃO
PROGRAMAÇÃO CONCORRENTE – 2015.1
Fábio M. Pereira
(fabio.mpereira@uesb.edu.br)
Roteiro
• Criando e executando uma daemon thread
• Processando exceções em uma thread
• Utilizando variáveis de tread locais
• Agrupando threads
• Processando exceções em um grupo de threads
• Criando threads através de uma fábrica
Criando e Executando Uma Daemon
Thread
• Java tem um tipo especial de thread chamada de daemon
thread
• Este tipo de thread tem prioridade muito baixa e
normalmente só é executada quando nenhuma outra
thread do mesmo programa está sendo executada
• Quando daemon threads são as únicas threads em
execução em um programa, a JVM termina o programa
terminando estas threads
• Com essas características, as daemon threads são
normalmente utilizadas como provedores de serviços
para threads normais (também chamadas de usuários)
em execução no mesmo programa
Criando e Executando Uma Daemon
Thread
• Elas geralmente têm um laço infinito que aguarda a
solicitação de serviço ou executa as tarefas da thread
• Elas não podem fazer tarefas importantes porque não
sabemos quando elas vão ter tempo de CPU e podem
terminar a qualquer momento se não existem quaisquer
outras threads em execução
• Um exemplo típico deste tipo de thread é o coletor de
lixo Java
• No exemplo utilizaremos duas threads: uma thread do
usuário que grava eventos em uma fila e uma daemon
que limpa essa fila, removendo os eventos que foram
gerados mais de 10 segundos atrás
Programa Exemplo
1. Crie a classe Event, esta classe só armazena informações
sobre os eventos que o nosso programa irá trabalhar.
Declare dois atributos particulares, um chamado date do
tipo java.util.Date e outro chamado de event do tipo
String. Gerar os métodos para escrever e ler seus valores.
2. Crie uma classe WriterTask e especifique que ela
implementa a interface Runnable.
public class WriterTask implements Runnable {
3. Declare a fila que armazena os eventos e implemente o
construtor da classe, que inicializa esta fila.
private Deque<Event> deque;
public WriterTask (Deque<Event> deque){
this.deque=deque;
}
Programa Exemplo
4. Implemente o método run() para esta tarefa. Este método deverá ter
um laço com 100 iterações. Cada iteração deverá criar um novo evento
(Event), salvá-lo na fila e dormir por um segundo.
@Override
public void run() {
for (int i=1; i<100; i++) {
Event event=new Event();
event.setDate(new Date());
event.setEvent(String.format("A thread %s gerou
um evento",Thread.currentThread().getId()));
deque.addFirst(event);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Programa Exemplo
5. Crie a classe CleanerTask e especifique que ela
estende a classe Thread.
public class CleanerTask extends Thread {
6. Declare a fila que armazena os eventos e implemente o
construtor da classe, que inicializa esta fila. No
construtor, marque esta thread como um daemon
através do método setDaemon().
private Deque<Event> deque;
public CleanerTask(Deque<Event> deque) {
this.deque = deque;
setDaemon(true);
}
Programa Exemplo
7. Implemente o método run(). Este método possui um
laço infinito que pega a data atual e chama o método
clean().
@Override
public void run() {
while (true) {
Date date = new Date();
clean(date);
}
}
Programa Exemplo
8. Implemente o método clean(). Ele pega o último evento
e, se foi criado mais de 10 segundos atrás, o apaga e
verifica o próximo evento. Se o evento é apagado,
escreve uma mensagem do evento e o novo tamanho da
fila, para acompanharmos a evolução.
private void clean(Date date) {
long difference;
boolean delete;
if (deque.size()==0) {
return;
}
delete=false;
...
Programa Exemplo
8. Continuação.
...
do {
Event e = deque.getLast();
difference = date.getTime() –
e.getDate().getTime();
if (difference > 10000) {
System.out.printf("Cleaner: %sn",e.getEvent());
deque.removeLast();
delete=true;
}
} while (difference > 10000);
if (delete){
System.out.printf("Cleaner: Tamanho da fila: %dn",
deque.size());
}
}
Programa Exemplo
9. Agora implemente a classe principal. Crie o método main().
public class Main {
public static void main(String[] args) {
10.Crie a fila para armazenar os eventos usando a classe Deque.
Deque<Event> deque=new ArrayDeque<Event>();
11.Crie e inicialize três threads WriterTask e uma
CleanerTask.
WriterTask writer=new WriterTask(deque);
for (int i=0; i<3; i++){
Thread thread=new Thread(writer);
thread.start();
}
CleanerTask cleaner=new CleanerTask(deque);
cleaner.start();
Programa Exemplo
12. Execute o programa e veja os resultados.
Funcionamento
• Se analisarmos a saída de uma execução do programa,
poderemos ver como a fila começa a crescer até que ela
tenha 30 eventos e, em seguida, o seu tamanho varia
entre 27 e 30 eventos até o final da execução
• O programa começa com três threads WriterTask,
cada thread escreve um evento e dorme durante um
segundo
• Após os primeiros 10 segundos, temos 30 threads na fila
• Durante estes 10 segundos CleanerTask vem
executando, enquanto as três threads WriterTask
estavam dormindo, mas não excluiu qualquer evento,
porque todos eles foram gerados menos de 10 segundos
atrás
Funcionamento
• Durante o resto da execução, CleanerTask exclui três
eventos a cada segundo e as três threads WriterTask
escrevem mais três, portanto, o tamanho da fila varia
entre 27 e 30 eventos
• Podemos brincar com o tempo em que as threads
WriterTask ficam dormindo: se usarmos um valor
menor, vamos ver que CleanerTask tem menos tempo
de CPU e o tamanho da fila vai aumentar porque
CleanerTask não exclui qualquer evento
Criando e Executando Uma Daemon
Thread
• Só podemos chamar o método setDaemon() antes de
chamar o método start(), uma vez que a thread está
sendo executada, não podemos modificar o seu estado
daemon
• Podemos usar o método isDaemon() para verificar se
uma thread é uma daemon thread (o método retorna
true) ou uma thread do usuário (o método retorna
false)
Processando Exceções em Uma Thread
• Existem dois tipos de exceções em Java:
– As exceções verificadas: essas exceções devem ser
especificadas na cláusula throws de um método ou capturadas
dentro dele, por exemplo, IOException ou
ClassNotFoundException
– Exceções não verificadas: essas exceções não têm que ser
especificadas ou capturadas, por exemplo,
NumberFormatException
• Quando uma exceção verificada é lançada dentro do
método run() de um objeto Thread, temos de capturá-
la e tratá-la, porque o método run() não aceita uma
cláusula throws
Processando Exceções em Uma Thread
• Quando uma exceção não verificada é lançada dentro do
método run() de um objeto Thread, o comportamento
padrão é escrever o rastreamento da pilha no console e
sair do programa
• Felizmente, Java nos fornece um mecanismo para
capturar e tratar as exceções não verificadas lançadas em
um objeto Thread para evitar que o programa termine
• Vamos aprender este mecanismo usando um exemplo
Programa Exemplo
1. Primeiro, temos de implementar uma classe para tratar
as exceções não verificadas. Esta classe deve
implementar a interface UncaughtExceptionHandler
e implementar o método uncaughtException()
declarado na interface. No nosso caso, chame essa
classe de ExceptionHandler e faça o método para
gravar informações sobre a Exception e a Thread
que a lançou. Veja o código a seguir.
Programa Exemplo
public class ExceptionHandler implements
UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e)
{
System.out.printf("Uma exceção foi capturadan");
System.out.printf("Thread: %sn",t.getId());
System.out.printf("Exception: %s: %sn",
e.getClass().getName(),e.getMessage());
System.out.printf("Stack Trace: n");
e.printStackTrace(System.out);
System.out.printf("Thread status: %sn",
t.getState());
}
}
Programa Exemplo
2. Agora, implemente uma classe que gera uma exceção
não verificada. Chame esta classe de Task, especifique
que ela implementa a interface Runnable, implemente
o método run(), e force a exceção, por exemplo, ao
tentar converter um valor de sequência de caracteres
em um valor int.
public class Task implements Runnable {
@Override
public void run() {
int numero=Integer.parseInt("TTT");
}
}
Programa Exemplo
3. Agora implemente a classe principal do exemplo.
Implemente uma classe chamada Main com o método
main().
public class Main {
public static void main(String[] args) {
4. Crie um objeto do tipo Task e uma Thread para executá-lo.
Defina o manipulador de exceção não verificada usando o
método setUncaughtExceptionHandler() e inicie a
execução da Thread.
Task task=new Task();
Thread thread=new Thread(task);
thread.setUncaughtExceptionHandler(
new ExceptionHandler());
thread.start();
}
}
Programa Exemplo
5. Execute o exemplo e veja os resultados.
Funcionamento
• A exceção é lançada e capturado pelo manipulador que
escreve no console as informações sobre a exceção e a
Thread que a lançou
• Quando uma exceção é lançada em uma thread e não é
capturada (tem que ser uma exceção não verificada), a
JVM verifica se a thread tem um manipulador de exceção
não capturada definido pelo método correspondente, se
tiver, a JVM invoca este método com os objetos Thread e
Exception como argumentos
• Se a thread não possui um manipulador de exceção não
capturada, o JVM imprime o rastreamento da pilha no
console e sai do programa
Processando Exceções em Uma Thread
• A classe Thread tem outro método relacionado com o
processo de exceções, ele é o método estático
setDefaultUncaughtExceptionHandler() que
estabelece um manipulador de exceção para todos os
objetos Thread da aplicação
Processando Exceções em Uma Thread
• Quando uma exceção não detectada é lançada em
Thread, a JVM procura por três manipuladores possíveis
para essa exceção:
– Primeiro, ele busca pelo manipulador de exceção não capturada
dos objetos Thread como aprendemos neste exemplo
– Se o manipulador não existe, então a JVM busca pelo
manipulador de exceção não capturada do ThreadGroup dos
objetos Thread como veremos adiante
– Se esse método não existe, a JVM busca pelo manipulador de
exceção não capturada padrão
– Se nenhum deles existe, a JVM imprime o rastreamento da pilha
da exceção no console e sai do programa
Utilizando Variáveis de Thread Locais
• Um dos aspectos mais críticos de uma aplicação
concorrente é o compartilhamento de dados
• Isto tem uma importância especial naqueles objetos que
estendem a classe Thread ou implementam a interface
Runnable
• Se você criar um objeto de uma classe que implementa a
interface Runnable e, em seguida, iniciar vários objetos
Thread usando o mesmo objeto Runnable, todos as
threads compartilham os mesmos atributos
• Isto significa que, se você alterar um atributo em uma
thread, todas as threads serão afetados por esta
mudança
Utilizando Variáveis de Thread Locais
• Às vezes, podemos estar interessados em ter um atributo
que não será compartilhado entre todas as threads que
executam o mesmo objeto
• A API de Concorrência Java fornece um mecanismo limpo
chamado de variáveis de threads locais com um
desempenho muito bom
• Neste exemplo, iremos desenvolver um programa que
tem o problema mostrado no início e outro programa
que resolve esse problema usando o mecanismo de
variáveis de threads locais
Programa Exemplo
1. Primeiro, vamos implementar um programa que tem o
problema exposto anteriormente. Crie uma classe
chamada UnsafeTask e especifique que ela
implementa a interface Runnable. Declare um atributo
java.util.Date privado.
public class UnsafeTask implements
Runnable{
private Date startDate;
2. Implemente o método run() do objeto UnsafeTask.
Este método irá inicializar o atributo startDate,
escrever o seu valor no console, esperar por um período
de tempo aleatório, e novamente escrever o valor do
atributo startDate.
Programa Exemplo
@Override
public void run() {
startDate=new Date();
System.out.printf(“Iniciando a Thread: %s :
%sn",Thread.currentThread().getId(),
startDate);
try {
TimeUnit.SECONDS.sleep((int)Math.rint(
Math.random()*10));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("Thread Finalizada: %s :
%sn",Thread.currentThread().getId(),
startDate);
}
Programa Exemplo
3. Agora, vamos implementar a classe principal desta aplicação
problemática. Crie uma classe chamada Main com um
método main(). Este método irá criar um objeto da classe
UnsafeTask e iniciar três threads usando esse objeto,
dormindo por 2 segundos entre cada thread.
public class Main {
public static void main(String[] args) {
UnsafeTask task=new UnsafeTask();
for (int i=0; i<3; i++){
Thread thread=new Thread(task);
thread.start();
try { TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
} } }
Programa Exemplo
4. Na captura de tela seguinte, podemos ver os resultados
da execução deste programa. Cada thread tem uma
hora de início diferentes, mas, quando terminam, todas
têm o mesmo valor no seu atributo startDate.
Programa Exemplo
5. Como mencionado anteriormente, iremos usar o mecanismo
de variáveis de thread locais para resolver este problema.
6. Crie uma classe chamada SafeTask e especifique que ela
implementa a interface Runnable.
public class SafeTask implements Runnable {
7. Declare um objeto da classe ThreadLocal<Date>. Este
objeto possuirá uma implementação implícita que inclui o
método initialValue(). Este método irá retornar a data
atual.
private static ThreadLocal<Date> startDate=
new ThreadLocal<Date>() {
protected Date initialValue(){
return new Date();
}
};
Programa Exemplo
8. Implemente o método run(). Este possui a mesma
funcionalidade do método run() de UnsafeClass, mas modifica
a maneira como acessa o atributo startDate.
@Override
public void run() {
System.out.printf("Iniciando Thread: %s :
%sn",Thread.currentThread().getId(),
startDate.get());
try {
TimeUnit.SECONDS.sleep((int)Math.rint(
Math.random()*10));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("Thread Finalizada: %s :
%sn",Thread.currentThread().getId(),
startDate.get());
}
Programa Exemplo
9. A classe principal deste exemplo é a mesma que a do
exemplo inseguro, mudando o nome da classe
Runnable.
10. Execute o exemplo e analise a diferença.
Funcionamento
• Agora, os três objetos Thread têm o seu próprio valor do
atributo startDate
• As variáveis de thread locais armazenam um valor de um
atributo para cada Thread que usa uma destas variáveis
• Podemos ler o valor usando o método get() e alterar o
valor usando o método set()
• A primeira vez que acessamos o valor de uma variável de
thread local, se ela não tem nenhum valor para o objeto
Thread que está chamando, a variável de thread local
chama o método initialValue() para atribuir um valor
para essa Thread e retorna o valor inicial
Utilizando Variáveis de Thread Locais
• A classe de thread local também fornece o método
remove(), que exclui o valor armazenado na variável de
thread local para a thread que está chamando
• A API de Concorrência Java inclui a classe
InheritableThreadLocal que fornece herança de
valores para threads criadas a partir de outra thread
• Se uma thread A tem um valor em uma variável de
thread local e criamos outra thread B, a thread B terá o
mesmo valor que a thread A na variável de thread local
• Podemos sobrescrever o método childValue() que é
chamado para inicializar o valor da thread filha na
variável de thread local, ele recebe o valor da thread pai
na variável de thread local como parâmetro
Agrupando Threads
• Uma funcionalidade interessante oferecida pela API de
Concorrência Java é a capacidade de agrupar as threads
• Isto permite-nos tratar as threads de um grupo como
uma unidade, proporcionando acesso aos objetos
Thread que pertencem a um grupo e realizar uma
operação com elas
• Por exemplo, temos algumas threads que fazem a mesma
tarefa e queremos controlá-las, independentemente de
quantas threads ainda estão em execução, o estado de
cada uma irá interromper todas elas com uma única
chamada
Agrupando Threads
• Java fornece a classe ThreadGroup para trabalhar com
grupos de threads
• Um objeto ThreadGroup pode ser formado por objetos
Thread e por outro objeto ThreadGroup, gerando uma
estrutura de árvore de threads
• Neste exemplo, trabalharemos com objetos
ThreadGroup desenvolvendo um exemplo simples:
teremos 10 threads dormindo durante um período de
tempo aleatório (simulando uma busca, por exemplo) e,
quando um deles acabar, iremos interromper o resto
Programa Exemplo
1. Primeiro, crie uma classe chamada Result. Ele irá
armazenar o nome da Thread que termina em primeiro
lugar. Declare um atributo privado String chamado name e
os métodos para ler e definir o valor.
2. Crie uma classe chamada SeachTask e especifique que ela
implementa a interface Runnable.
public class SearchTask implements Runnable {
3. Declare um atributo privado da classe Result e implemente
o construtor da classe que inicializa este atributo.
private Result result;
public SearchTask(Result result) {
this.result=result;
}
Programa Exemplo
4. Implemente o método run(). Ele vai chamar o método
doTask() e esperar que ele termine ou por uma
exceção InterruptedException. O método gravará
mensagens para indicar o início, fim ou interrupção
desta Thread.
@Override
public void run() {
...
Programa Exemplo
@Override
public void run() {
String name=Thread.currentThread().getName();
System.out.printf("Thread %s:
Iniciadan",name);
try {
doTask();
result.setName(name);
} catch (InterruptedException e) {
System.out.printf("Thread %s:
Interrompidan",name);
return;
}
System.out.printf("Thread %s:
Terminadan",name);
}
Programa Exemplo
5. Implemente o método doTask(). Ele irá criar um objeto
Random para gerar um número aleatório e chamará o
método sleep() com o número gerado.
private void doTask() throws
InterruptedException {
Random random=new Random((new Date())
.getTime());
int value=(int)(random.nextDouble()*100);
System.out.printf("Thread %s: %dn",
Thread.currentThread().getName(),
value);
TimeUnit.SECONDS.sleep(value);
}
Programa Exemplo
6. Agora crie a classe principal do exemplo e implemente o
método main().
public class Main {
public static void main(String[] args) {
7. Primeiro, crie um objeto ThreadGroup e o chame de
Searcher.
ThreadGroup threadGroup = new
ThreadGroup("Searcher");
8. Então, crie um objeto SearchTask e um objeto Result.
Result result=new Result();
SearchTask searchTask = new
SearchTask(result);
Programa Exemplo
9. Agora, crie 10 objetos Thread usando o objeto
SearchTask. Quando você chamar o construtor da
classe Thread, passe como primeiro argumento o
objeto ThreadGroup.
for (int i=0; i<10; i++) {
Thread thread=new Thread(threadGroup,
searchTask);
thread.start();
try { TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Programa Exemplo
10. Imprima informação sobre o objeto ThreadGroup
usando o método list().
System.out.printf("Número de Threads: %dn",
threadGroup.activeCount());
System.out.printf("Informação sobre o Grupo
de Threadsn");
threadGroup.list();
Programa Exemplo
11. Use os métodos activeCount() e enumerate() para saber
quantos objetos Thread estão associados ao objeto
ThreadGroup e obter uma lista deles. Podemos usar esse
método para obter, por exemplo, o estado de cada Thread.
Thread[] threads=new
Thread[threadGroup.activeCount()];
threadGroup.enumerate(threads);
for (int i=0; i<threadGroup.activeCount();
i++) {
System.out.printf("Thread %s: %sn",
threads[i].getName(),
threads[i].getState());
}
Programa Exemplo
12. Chame o método waitFinish(). Iremos implementá-lo
adiante. Ele irá esperar até que uma das threads do
objeto ThreadGroup termine.
waitFinish(threadGroup);
13. Interrompa o restante das threads do grupo usando o
método interrupt().
threadGroup.interrupt();
Programa Exemplo
14. Implemente o método waitFinish(). Ele irá usar o
método activeCount() para controlar o final de uma
das threads.
private static void waitFinish(ThreadGroup
threadGroup) {
while (threadGroup.activeCount()>9) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Programa Exemplo
15. Execute o exemplo e veja o resultado.
Programa Exemplo
15. Execute o exemplo e veja o resultado.
Programa Exemplo
15. Execute o exemplo e veja o resultado.
Funcionamento
• Na captura de tela, podemos ver a saída do método
list() e a saída gerada quando escrevemos o estado de
cada objeto Thread
• A classe ThreadGroup armazena os objetos Thread e
outros objetos ThreadGroup associados a ela, de modo
que ela pode acessar todas as suas informações (estado,
por exemplo) e executar operações sobre todos os seus
membros (interromper, por exemplo)
• A classe ThreadGroup possiu mais métodos, verifique a
documentação da API para ter uma explicação completa
de todos esses métodos
Processando Exceções em Um Grupo de
Threads
• Um aspecto muito importante em toda linguagem de
programação é o mecanismo que fornece gerenciamento
de situações de erro na aplicação
• A linguagem Java, como quase todas as linguagens de
programação modernas, implementa um mecanismo
baseado em exceção para gerir situações de erro
• Ela fornece uma série de classes para representar erros
diferentes
• Essas exceções são lançadas pelas classes Java quando
uma situação de erro é detectada
• Podemos usar essas exceções, ou implementar nossas
próprias exceções, para gerenciar os erros produzidos em
nossas classes
Processando Exceções em Um Grupo de
Threads
• Java também fornece um mecanismo para capturar e
processar essas exceções
• Há exceções que devem ser capturados ou re-lançadas
usando a cláusula throws de um método, essas exceções são
chamados de exceções verificadas
• Há exceções que não têm de ser especificadas ou capturados,
estas são as exceções não verificadas
• No tópico, Controlando a Interrupção de uma Thread, vimos
como usar um método genérico para processar todas as
exceções não verificadas que são lançadas em um objeto
Thread
• Outra possibilidade é estabelecer um método que captura
todas as exceções não capturadas, lançadas por qualquer
Thread da classe ThreadGroup
Programa Exemplo
1. Em primeiro lugar, temos de estender a classe
ThreadGroup criando uma classe chamada
MyThreadGroup. Temos de declarar um construtor com
um parâmetro, porque a classe ThreadGroup não tem
um construtor sem ele.
public class MyThreadGroup extends
ThreadGroup {
public MyThreadGroup(String name) {
super(name);
}
Programa Exemplo
2. Substitua o método uncaughtException(). Este método
é chamado quando uma exceção é lançada em uma das
threads da classe ThreadGroup. Neste caso, este método
irá escrever no console informações sobre a exceção e da
Thread que a lança, e interromper o restante das threads
na classe ThreadGroup.
@Override
public void uncaughtException(Thread t,
Throwable e) {
System.out.printf("A thread %s lançou uma
Exceçãon",t.getId());
e.printStackTrace(System.out);
System.out.printf("Terminando o restante das
Threadsn");
interrupt();
}
Programa Exemplo
3. Crie uma classe chamada Task e especifique que ele
implementa a interface Runnable.
public class Task implements Runnable {
4. Implemente o método run(). Neste caso, vamos
provocar uma exceção AritmethicException. Para
isso, vamos dividir 1.000 entre números aleatórios até
que o gerador random gere um zero e a exceção seja
lançada.
@Override
public void run() {
...
Programa Exemplo
@Override
public void run() {
int result;
Random random=new Random(Thread.currentThread()
.getId());
while (true) {
result=1000/((int)(random.nextDouble()
*1000));
System.out.printf("%s : %dn", Thread
.currentThread().getId(),result);
if (Thread.currentThread().isInterrupted()) {
System.out.printf("%d : Interrompidan",Thread.
currentThread().getId());
return;
}
}
}
Programa Exemplo
5. Agora, vamos implementar a classe principal do
exemplo e o método main().
public class Main {
public static void main(String[] args) {
6. Crie um objeto da classe MyThreadGroup.
MyThreadGroup threadGroup=new
MyThreadGroup("MyThreadGroup");
7. Crie um objeto da classe Task.
Task task=new Task();
Programa Exemplo
8. Crie dois objetos Thread com esta Task e inicie-os.
for (int i=0; i<2; i++){
Thread t=new Thread(threadGroup,task);
t.start();
}
9. Execute o exemplo e veja os resultados.
Funcionamento
• Quando executamos o exemplo, vemos como um dos objetos
Thread lança a exceção e o outro é interrompido
• Quando uma exceção não detectada é lançada em Thread, a
JVM procura três possíveis manipuladores para essa exceção:
– Primeiro, ela busca pelo manipulador de exceção não capturada da
thread, como foi explicado em tópico anterior
– Se o manipulador não existe, então a JVM busca pelo manipulador de
exceção não capturada da classe ThreadGroup da thread, como
vimos neste exemplo
– Se esse método não existe, a JVM busca pelo manipulador de exceção
não capturada padrão
• Se nenhum dos manipuladores existir, a JVM escreve o
rastreamento da pilha de exceção no console e sai do
programa
Criando Threads Através de Uma Fábrica
• O padrão fábrica de objetos é um dos design patterns mais
utilizados no mundo da programação orientada a objetos
• É um padrão criacional e seu objetivo é desenvolver um
objeto cuja missão será a criação de outros objetos de uma
ou de várias classes
• Então, quando nós queremos criar um objeto de uma dessas
classes, usamos a fábrica em vez de usar o operador new
• Com esta fábrica, nós centralizamos a criação de objetos com
algumas vantagens:
– É fácil alterar a classe dos objetos criados ou a forma como criar esses
objetos
– É fácil limitar a criação de objetos para recursos limitados, por
exemplo, nós só podemos ter n objetos de um tipo
– É fácil gerar dados estatísticos sobre a criação dos objetos
Criando Threads Através de Uma Fábrica
• Java fornece uma interface, a interface ThreadFactory
para implementar uma fábrica de objetos Thread
• Alguns utilitários avançados da API de concorrência Java
usam fábricas de threads para criar threads
• Neste exemplo, vamos implementar uma interface
ThreadFactory para criar objetos Thread com um nome
personalizado, enquanto iremos salvar as estatísticas dos
objetos Thread criados
Programa Exemplo
1. Crie uma classe chamada MyThreadFactory e
especifique que ele implementa a interface
ThreadFactory.
public class MyThreadFactory implements
ThreadFactory
2. Declare três atributos: um número inteiro chamado de
counter, que vamos usar para armazenar o número do
objeto Thread criado, uma String denominada name
com o nome base de cada Thread criada, e uma lista
(List) de objetos String chamada stats para salvar os
dados estatísticos sobre os objetos Thread criados.
Devemos também implementar o construtor da classe
que inicializa esses atributos.
Programa Exemplo
private int counter;
private String name;
private List<String> stats;
public MyThreadFactory(String name){
counter=0;
this.name=name;
stats=new ArrayList<String>();
}
Programa Exemplo
3. Implementar o método newThread(). Este método irá
receber uma interface Runnable e retorna um objeto
Thread para esta interface Runnable. No nosso caso, nós
geramos o nome do objeto Thread, criamos o novo objeto
Thread, e salvamos as estatísticas.
@Override
public Thread newThread(Runnable r) {
Thread t=new Thread(r,name+"-Thread_"
+counter);
counter++;
stats.add(String.format("Thread %d criada
com o nome %s em %sn",t.getId(),
t.getName(),new Date()));
return t;
}
Programa Exemplo
4. Implemente o método getStatistics() que retorna
um objeto String com os dados estatísticos de todos os
objetos Thread criados.
public String getStats(){
StringBuffer buffer=new StringBuffer();
Iterator<String> it = stats.iterator();
while (it.hasNext()) {
buffer.append(it.next());
}
return buffer.toString();
}
Programa Exemplo
5. Crie uma classe chamada Task e especifique que ela
implementa a interface Runnable. Neste exemplo, essas
tarefas não vão fazer nada além que dormir por um
segundo.
public class Task implements Runnable {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Programa Exemplo
6. Crie a classe principal do exemplo e implemente o método
main().
public class Main {
public static void main(String[] args) {
7. Crie um objeto MyThreadFactory e um objeto Task.
MyThreadFactory factory=new
MyThreadFactory("MyThreadFactory");
Task task=new Task();
8. Crie 10 objetos Thread usando o objeto MyThreadFactory
e os inicie.
Thread thread;
System.out.printf("Iniciando as Threadsn");
for (int i=0; i<10; i++){
thread=factory.newThread(task);
thread.start();
}
Programa Exemplo
9. Escreva no console as estatísticas da fabrica de threads.
System.out.printf("Estatísticas:n");
System.out.printf("%sn",factory.getStats());
10. Execute o exemplo e veja os resultados.
Funcionamento
• A interface ThreadFactory tem apenas um método
chamado newThread
• Ele recebe um objeto Runnable como parâmetro e
retorna um objeto Thread
• Quando implementamos uma interface ThreadFactory,
temos que implementar essa interface e substituir esse
método
• A maioria das ThreadFactory básicas, têm apenas uma
única linha:
return new Thread(r);
Funcionamento
• Podemos melhorar esta aplicação, adicionando algumas
variantes:
– Criando threads personalizadas, como no exemplo, usando um
formato especial para o nome ou até mesmo criando nossa própria
classe Thread que herda da classe Thread Java
– Salvando estatísticas de criação de threads, como mostrado no
exemplo anterior
– Limitando o número de threads criadas
– Validando a criação das threads
– E mais o que possamos imaginar
• O uso do padrão de design de fábrica é uma boa prática de
programação, mas, se implementarmos uma interface
ThreadFactory para centralizar a criação de threads, temos
que rever o código para garantir que todas as threads são
criadas usando essa fábrica
UNIVERSIDADE ESTADUAL DO SUDOESTE DA BAHIA
CURSO DE CIÊNCIA DA COMPUTAÇÃO
PROGRAMAÇÃO CONCORRENTE – 2015.1
Fábio M. Pereira
(fabio.mpereira@uesb.edu.br)

Mais conteúdo relacionado

Mais procurados (19)

Java recursos avançados - multithreading
Java   recursos avançados - multithreadingJava   recursos avançados - multithreading
Java recursos avançados - multithreading
 
Java11
Java11Java11
Java11
 
Java introdução ao java
Java   introdução ao javaJava   introdução ao java
Java introdução ao java
 
Java 13
Java 13Java 13
Java 13
 
Java13
Java13Java13
Java13
 
Aula5
Aula5Aula5
Aula5
 
Apostila: Curso de java III
Apostila: Curso de java IIIApostila: Curso de java III
Apostila: Curso de java III
 
Java 16
Java 16Java 16
Java 16
 
Java orientação a objetos (variaveis de instancia e metodos)
Java   orientação a objetos (variaveis de instancia e metodos)Java   orientação a objetos (variaveis de instancia e metodos)
Java orientação a objetos (variaveis de instancia e metodos)
 
Curso Java I
Curso Java ICurso Java I
Curso Java I
 
Fundamentos de Objetos Remotos
Fundamentos de Objetos RemotosFundamentos de Objetos Remotos
Fundamentos de Objetos Remotos
 
Threads 03: Ciclo de vida, aplicações e boas práticas
Threads 03: Ciclo de vida, aplicações e boas práticasThreads 03: Ciclo de vida, aplicações e boas práticas
Threads 03: Ciclo de vida, aplicações e boas práticas
 
Conhecendo o Spring
Conhecendo o SpringConhecendo o Spring
Conhecendo o Spring
 
Java 06
Java 06Java 06
Java 06
 
Java6
Java6Java6
Java6
 
Curso Java Básico - Aula 04
Curso Java Básico - Aula 04Curso Java Básico - Aula 04
Curso Java Básico - Aula 04
 
Threads 05: Travas de Exclusão Mútua
Threads 05: Travas de Exclusão MútuaThreads 05: Travas de Exclusão Mútua
Threads 05: Travas de Exclusão Mútua
 
Threads 09: Paralelismo
Threads 09: ParalelismoThreads 09: Paralelismo
Threads 09: Paralelismo
 
Curso Java Básico - Aula02
Curso Java Básico - Aula02Curso Java Básico - Aula02
Curso Java Básico - Aula02
 

Destaque

Desenvolvimento de Sistemas Web - HTML5 - Introdução
Desenvolvimento de Sistemas Web - HTML5 - IntroduçãoDesenvolvimento de Sistemas Web - HTML5 - Introdução
Desenvolvimento de Sistemas Web - HTML5 - IntroduçãoFabio Moura Pereira
 
Aula de Desenvolvimento de Sistemas Web - CSS3
Aula de Desenvolvimento de Sistemas Web - CSS3Aula de Desenvolvimento de Sistemas Web - CSS3
Aula de Desenvolvimento de Sistemas Web - CSS3Fabio Moura Pereira
 
Curso de Desenvolvimento de Sistemas Web - (X)HTML
Curso de Desenvolvimento de Sistemas Web - (X)HTMLCurso de Desenvolvimento de Sistemas Web - (X)HTML
Curso de Desenvolvimento de Sistemas Web - (X)HTMLFabio Moura Pereira
 
Aula Interface Gráfica do Usuário
Aula Interface Gráfica do UsuárioAula Interface Gráfica do Usuário
Aula Interface Gráfica do UsuárioFabio Moura Pereira
 
Desenvolvimento de Sistemas Web - Conceitos Básicos
Desenvolvimento de Sistemas Web - Conceitos BásicosDesenvolvimento de Sistemas Web - Conceitos Básicos
Desenvolvimento de Sistemas Web - Conceitos BásicosFabio Moura Pereira
 
Aula de Prolog 07 - Estruturas de Dados
Aula de Prolog 07 - Estruturas de DadosAula de Prolog 07 - Estruturas de Dados
Aula de Prolog 07 - Estruturas de DadosFabio Moura Pereira
 
Aula de Prolog 08 - Unificação
Aula de Prolog 08 - UnificaçãoAula de Prolog 08 - Unificação
Aula de Prolog 08 - UnificaçãoFabio Moura Pereira
 
Desenvolvimento de Jogos - Mercado Parte 2
Desenvolvimento de Jogos - Mercado Parte 2Desenvolvimento de Jogos - Mercado Parte 2
Desenvolvimento de Jogos - Mercado Parte 2Fabio Moura Pereira
 
Desenvolvimento de Jogos - Game Design
Desenvolvimento de Jogos - Game DesignDesenvolvimento de Jogos - Game Design
Desenvolvimento de Jogos - Game DesignFabio Moura Pereira
 

Destaque (20)

Aula Prolog - 05
Aula Prolog - 05Aula Prolog - 05
Aula Prolog - 05
 
Haskell - Introdução
Haskell - IntroduçãoHaskell - Introdução
Haskell - Introdução
 
Desenvolvimento de Sistemas Web - HTML5 - Introdução
Desenvolvimento de Sistemas Web - HTML5 - IntroduçãoDesenvolvimento de Sistemas Web - HTML5 - Introdução
Desenvolvimento de Sistemas Web - HTML5 - Introdução
 
Aula de Desenvolvimento de Sistemas Web - CSS3
Aula de Desenvolvimento de Sistemas Web - CSS3Aula de Desenvolvimento de Sistemas Web - CSS3
Aula de Desenvolvimento de Sistemas Web - CSS3
 
Aula 05 - Java Script Básico
Aula 05 -  Java Script BásicoAula 05 -  Java Script Básico
Aula 05 - Java Script Básico
 
Curso de Desenvolvimento de Sistemas Web - (X)HTML
Curso de Desenvolvimento de Sistemas Web - (X)HTMLCurso de Desenvolvimento de Sistemas Web - (X)HTML
Curso de Desenvolvimento de Sistemas Web - (X)HTML
 
Aula Prolog 03
Aula Prolog 03Aula Prolog 03
Aula Prolog 03
 
Aula Persistência 01 (Java)
Aula Persistência 01 (Java)Aula Persistência 01 (Java)
Aula Persistência 01 (Java)
 
Aula Interface Gráfica do Usuário
Aula Interface Gráfica do UsuárioAula Interface Gráfica do Usuário
Aula Interface Gráfica do Usuário
 
Desenvolvimento de Sistemas Web - Conceitos Básicos
Desenvolvimento de Sistemas Web - Conceitos BásicosDesenvolvimento de Sistemas Web - Conceitos Básicos
Desenvolvimento de Sistemas Web - Conceitos Básicos
 
Aula Java Swing
Aula Java SwingAula Java Swing
Aula Java Swing
 
Curso de PHP - Objetos
Curso de PHP - ObjetosCurso de PHP - Objetos
Curso de PHP - Objetos
 
Aula de Prolog 07 - Estruturas de Dados
Aula de Prolog 07 - Estruturas de DadosAula de Prolog 07 - Estruturas de Dados
Aula de Prolog 07 - Estruturas de Dados
 
Aula de Prolog 08 - Unificação
Aula de Prolog 08 - UnificaçãoAula de Prolog 08 - Unificação
Aula de Prolog 08 - Unificação
 
Aula Prolog 02
Aula Prolog 02Aula Prolog 02
Aula Prolog 02
 
Prolog 04 - Regras
Prolog 04 - RegrasProlog 04 - Regras
Prolog 04 - Regras
 
Aula Prolog 01
Aula Prolog 01Aula Prolog 01
Aula Prolog 01
 
Aula de Prolog 06 - Recursão
Aula de Prolog 06 - RecursãoAula de Prolog 06 - Recursão
Aula de Prolog 06 - Recursão
 
Desenvolvimento de Jogos - Mercado Parte 2
Desenvolvimento de Jogos - Mercado Parte 2Desenvolvimento de Jogos - Mercado Parte 2
Desenvolvimento de Jogos - Mercado Parte 2
 
Desenvolvimento de Jogos - Game Design
Desenvolvimento de Jogos - Game DesignDesenvolvimento de Jogos - Game Design
Desenvolvimento de Jogos - Game Design
 

Semelhante a 04 - Gerenciamento de Threads - II

Threads 01: Criação e controle de threads
Threads 01: Criação e controle de threadsThreads 01: Criação e controle de threads
Threads 01: Criação e controle de threadsHelder da Rocha
 
Threads 08: Executores e Futures
Threads 08: Executores e FuturesThreads 08: Executores e Futures
Threads 08: Executores e FuturesHelder da Rocha
 
Curso Java Basico] Aula 67: Criando Threads + metodos start, run e sleep
Curso Java Basico] Aula 67: Criando Threads + metodos start, run e sleepCurso Java Basico] Aula 67: Criando Threads + metodos start, run e sleep
Curso Java Basico] Aula 67: Criando Threads + metodos start, run e sleepLoiane Groner
 
Programação Concorrente - Aula 03
Programação Concorrente - Aula 03Programação Concorrente - Aula 03
Programação Concorrente - Aula 03thomasdacosta
 
Utilitários para Programação Concorrente em Java (2005)
Utilitários para Programação Concorrente em Java (2005)Utilitários para Programação Concorrente em Java (2005)
Utilitários para Programação Concorrente em Java (2005)Helder da Rocha
 
Funcamentos de Programação Concorrente
Funcamentos de Programação ConcorrenteFuncamentos de Programação Concorrente
Funcamentos de Programação ConcorrenteDenis L Presciliano
 
Excecoes
ExcecoesExcecoes
ExcecoesEMSNEWS
 
Delphi Conference 2012 - Controlando a Concorrência em Aplicações Multi-Thread
Delphi Conference 2012 - Controlando a Concorrência em Aplicações Multi-ThreadDelphi Conference 2012 - Controlando a Concorrência em Aplicações Multi-Thread
Delphi Conference 2012 - Controlando a Concorrência em Aplicações Multi-ThreadMario Guedes
 

Semelhante a 04 - Gerenciamento de Threads - II (20)

Curso de Java: Threads
Curso de Java: ThreadsCurso de Java: Threads
Curso de Java: Threads
 
Threads 01: Criação e controle de threads
Threads 01: Criação e controle de threadsThreads 01: Criação e controle de threads
Threads 01: Criação e controle de threads
 
Threads 08: Executores e Futures
Threads 08: Executores e FuturesThreads 08: Executores e Futures
Threads 08: Executores e Futures
 
Java1
Java1Java1
Java1
 
Curso Java Basico] Aula 67: Criando Threads + metodos start, run e sleep
Curso Java Basico] Aula 67: Criando Threads + metodos start, run e sleepCurso Java Basico] Aula 67: Criando Threads + metodos start, run e sleep
Curso Java Basico] Aula 67: Criando Threads + metodos start, run e sleep
 
threads e-sockets-em-java
 threads e-sockets-em-java threads e-sockets-em-java
threads e-sockets-em-java
 
Programação Concorrente - Aula 03
Programação Concorrente - Aula 03Programação Concorrente - Aula 03
Programação Concorrente - Aula 03
 
Utilitários para Programação Concorrente em Java (2005)
Utilitários para Programação Concorrente em Java (2005)Utilitários para Programação Concorrente em Java (2005)
Utilitários para Programação Concorrente em Java (2005)
 
THREADS EM JAVA: INTRODUÇÃO
THREADS EM JAVA: INTRODUÇÃOTHREADS EM JAVA: INTRODUÇÃO
THREADS EM JAVA: INTRODUÇÃO
 
Linguagem Java- Iniciação à programação Java
Linguagem Java- Iniciação à programação JavaLinguagem Java- Iniciação à programação Java
Linguagem Java- Iniciação à programação Java
 
Java 13 Excecoes
Java 13 ExcecoesJava 13 Excecoes
Java 13 Excecoes
 
Thread Java
Thread JavaThread Java
Thread Java
 
Funcamentos de Programação Concorrente
Funcamentos de Programação ConcorrenteFuncamentos de Programação Concorrente
Funcamentos de Programação Concorrente
 
POO - 22 - Tratamento de Exceções em Java
POO - 22 - Tratamento de Exceções em JavaPOO - 22 - Tratamento de Exceções em Java
POO - 22 - Tratamento de Exceções em Java
 
J530 14 xdoclet
J530 14 xdocletJ530 14 xdoclet
J530 14 xdoclet
 
Excepções JAVA
Excepções JAVAExcepções JAVA
Excepções JAVA
 
Programação Defensiva
Programação DefensivaProgramação Defensiva
Programação Defensiva
 
Threads
ThreadsThreads
Threads
 
Excecoes
ExcecoesExcecoes
Excecoes
 
Delphi Conference 2012 - Controlando a Concorrência em Aplicações Multi-Thread
Delphi Conference 2012 - Controlando a Concorrência em Aplicações Multi-ThreadDelphi Conference 2012 - Controlando a Concorrência em Aplicações Multi-Thread
Delphi Conference 2012 - Controlando a Concorrência em Aplicações Multi-Thread
 

Mais de Fabio Moura Pereira

Programação Concorrente - Objetos e Concorrência
Programação Concorrente - Objetos e ConcorrênciaProgramação Concorrente - Objetos e Concorrência
Programação Concorrente - Objetos e ConcorrênciaFabio Moura Pereira
 
Programação Concorrente - Introdução
Programação Concorrente - IntroduçãoProgramação Concorrente - Introdução
Programação Concorrente - IntroduçãoFabio Moura Pereira
 
Aula - Interfaces e Estilos de Interação
Aula - Interfaces e Estilos de InteraçãoAula - Interfaces e Estilos de Interação
Aula - Interfaces e Estilos de InteraçãoFabio Moura Pereira
 
Aula Desenvolvimento de Jogos - Game Engine (Motor de Jogos)
Aula Desenvolvimento de Jogos - Game Engine (Motor de Jogos)Aula Desenvolvimento de Jogos - Game Engine (Motor de Jogos)
Aula Desenvolvimento de Jogos - Game Engine (Motor de Jogos)Fabio Moura Pereira
 
Desenvolvimento de Jogos - Mercado Parte 1
Desenvolvimento de Jogos - Mercado Parte 1Desenvolvimento de Jogos - Mercado Parte 1
Desenvolvimento de Jogos - Mercado Parte 1Fabio Moura Pereira
 

Mais de Fabio Moura Pereira (11)

Aula Prolog 09 - Listas
Aula Prolog 09 - ListasAula Prolog 09 - Listas
Aula Prolog 09 - Listas
 
Programação Concorrente - Objetos e Concorrência
Programação Concorrente - Objetos e ConcorrênciaProgramação Concorrente - Objetos e Concorrência
Programação Concorrente - Objetos e Concorrência
 
Programação Concorrente - Introdução
Programação Concorrente - IntroduçãoProgramação Concorrente - Introdução
Programação Concorrente - Introdução
 
Aula - Interfaces e Estilos de Interação
Aula - Interfaces e Estilos de InteraçãoAula - Interfaces e Estilos de Interação
Aula - Interfaces e Estilos de Interação
 
Aula Desenvolvimento de Jogos - Game Engine (Motor de Jogos)
Aula Desenvolvimento de Jogos - Game Engine (Motor de Jogos)Aula Desenvolvimento de Jogos - Game Engine (Motor de Jogos)
Aula Desenvolvimento de Jogos - Game Engine (Motor de Jogos)
 
Padrões de Projeto de Software
Padrões de Projeto de SoftwarePadrões de Projeto de Software
Padrões de Projeto de Software
 
Curso de PHP - Arrays
Curso de PHP - ArraysCurso de PHP - Arrays
Curso de PHP - Arrays
 
Desenvolvimento de Jogos - Mercado Parte 1
Desenvolvimento de Jogos - Mercado Parte 1Desenvolvimento de Jogos - Mercado Parte 1
Desenvolvimento de Jogos - Mercado Parte 1
 
PHP - Funções
PHP - FunçõesPHP - Funções
PHP - Funções
 
PHP - Introdução
PHP - IntroduçãoPHP - Introdução
PHP - Introdução
 
PHP - Strings
PHP - StringsPHP - Strings
PHP - Strings
 

04 - Gerenciamento de Threads - II

  • 1. UNIVERSIDADE ESTADUAL DO SUDOESTE DA BAHIA CURSO DE CIÊNCIA DA COMPUTAÇÃO PROGRAMAÇÃO CONCORRENTE – 2015.1 Fábio M. Pereira (fabio.mpereira@uesb.edu.br)
  • 2. Roteiro • Criando e executando uma daemon thread • Processando exceções em uma thread • Utilizando variáveis de tread locais • Agrupando threads • Processando exceções em um grupo de threads • Criando threads através de uma fábrica
  • 3.
  • 4. Criando e Executando Uma Daemon Thread • Java tem um tipo especial de thread chamada de daemon thread • Este tipo de thread tem prioridade muito baixa e normalmente só é executada quando nenhuma outra thread do mesmo programa está sendo executada • Quando daemon threads são as únicas threads em execução em um programa, a JVM termina o programa terminando estas threads • Com essas características, as daemon threads são normalmente utilizadas como provedores de serviços para threads normais (também chamadas de usuários) em execução no mesmo programa
  • 5. Criando e Executando Uma Daemon Thread • Elas geralmente têm um laço infinito que aguarda a solicitação de serviço ou executa as tarefas da thread • Elas não podem fazer tarefas importantes porque não sabemos quando elas vão ter tempo de CPU e podem terminar a qualquer momento se não existem quaisquer outras threads em execução • Um exemplo típico deste tipo de thread é o coletor de lixo Java • No exemplo utilizaremos duas threads: uma thread do usuário que grava eventos em uma fila e uma daemon que limpa essa fila, removendo os eventos que foram gerados mais de 10 segundos atrás
  • 6. Programa Exemplo 1. Crie a classe Event, esta classe só armazena informações sobre os eventos que o nosso programa irá trabalhar. Declare dois atributos particulares, um chamado date do tipo java.util.Date e outro chamado de event do tipo String. Gerar os métodos para escrever e ler seus valores. 2. Crie uma classe WriterTask e especifique que ela implementa a interface Runnable. public class WriterTask implements Runnable { 3. Declare a fila que armazena os eventos e implemente o construtor da classe, que inicializa esta fila. private Deque<Event> deque; public WriterTask (Deque<Event> deque){ this.deque=deque; }
  • 7. Programa Exemplo 4. Implemente o método run() para esta tarefa. Este método deverá ter um laço com 100 iterações. Cada iteração deverá criar um novo evento (Event), salvá-lo na fila e dormir por um segundo. @Override public void run() { for (int i=1; i<100; i++) { Event event=new Event(); event.setDate(new Date()); event.setEvent(String.format("A thread %s gerou um evento",Thread.currentThread().getId())); deque.addFirst(event); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } }
  • 8. Programa Exemplo 5. Crie a classe CleanerTask e especifique que ela estende a classe Thread. public class CleanerTask extends Thread { 6. Declare a fila que armazena os eventos e implemente o construtor da classe, que inicializa esta fila. No construtor, marque esta thread como um daemon através do método setDaemon(). private Deque<Event> deque; public CleanerTask(Deque<Event> deque) { this.deque = deque; setDaemon(true); }
  • 9. Programa Exemplo 7. Implemente o método run(). Este método possui um laço infinito que pega a data atual e chama o método clean(). @Override public void run() { while (true) { Date date = new Date(); clean(date); } }
  • 10. Programa Exemplo 8. Implemente o método clean(). Ele pega o último evento e, se foi criado mais de 10 segundos atrás, o apaga e verifica o próximo evento. Se o evento é apagado, escreve uma mensagem do evento e o novo tamanho da fila, para acompanharmos a evolução. private void clean(Date date) { long difference; boolean delete; if (deque.size()==0) { return; } delete=false; ...
  • 11. Programa Exemplo 8. Continuação. ... do { Event e = deque.getLast(); difference = date.getTime() – e.getDate().getTime(); if (difference > 10000) { System.out.printf("Cleaner: %sn",e.getEvent()); deque.removeLast(); delete=true; } } while (difference > 10000); if (delete){ System.out.printf("Cleaner: Tamanho da fila: %dn", deque.size()); } }
  • 12. Programa Exemplo 9. Agora implemente a classe principal. Crie o método main(). public class Main { public static void main(String[] args) { 10.Crie a fila para armazenar os eventos usando a classe Deque. Deque<Event> deque=new ArrayDeque<Event>(); 11.Crie e inicialize três threads WriterTask e uma CleanerTask. WriterTask writer=new WriterTask(deque); for (int i=0; i<3; i++){ Thread thread=new Thread(writer); thread.start(); } CleanerTask cleaner=new CleanerTask(deque); cleaner.start();
  • 13. Programa Exemplo 12. Execute o programa e veja os resultados.
  • 14. Funcionamento • Se analisarmos a saída de uma execução do programa, poderemos ver como a fila começa a crescer até que ela tenha 30 eventos e, em seguida, o seu tamanho varia entre 27 e 30 eventos até o final da execução • O programa começa com três threads WriterTask, cada thread escreve um evento e dorme durante um segundo • Após os primeiros 10 segundos, temos 30 threads na fila • Durante estes 10 segundos CleanerTask vem executando, enquanto as três threads WriterTask estavam dormindo, mas não excluiu qualquer evento, porque todos eles foram gerados menos de 10 segundos atrás
  • 15. Funcionamento • Durante o resto da execução, CleanerTask exclui três eventos a cada segundo e as três threads WriterTask escrevem mais três, portanto, o tamanho da fila varia entre 27 e 30 eventos • Podemos brincar com o tempo em que as threads WriterTask ficam dormindo: se usarmos um valor menor, vamos ver que CleanerTask tem menos tempo de CPU e o tamanho da fila vai aumentar porque CleanerTask não exclui qualquer evento
  • 16. Criando e Executando Uma Daemon Thread • Só podemos chamar o método setDaemon() antes de chamar o método start(), uma vez que a thread está sendo executada, não podemos modificar o seu estado daemon • Podemos usar o método isDaemon() para verificar se uma thread é uma daemon thread (o método retorna true) ou uma thread do usuário (o método retorna false)
  • 17.
  • 18. Processando Exceções em Uma Thread • Existem dois tipos de exceções em Java: – As exceções verificadas: essas exceções devem ser especificadas na cláusula throws de um método ou capturadas dentro dele, por exemplo, IOException ou ClassNotFoundException – Exceções não verificadas: essas exceções não têm que ser especificadas ou capturadas, por exemplo, NumberFormatException • Quando uma exceção verificada é lançada dentro do método run() de um objeto Thread, temos de capturá- la e tratá-la, porque o método run() não aceita uma cláusula throws
  • 19. Processando Exceções em Uma Thread • Quando uma exceção não verificada é lançada dentro do método run() de um objeto Thread, o comportamento padrão é escrever o rastreamento da pilha no console e sair do programa • Felizmente, Java nos fornece um mecanismo para capturar e tratar as exceções não verificadas lançadas em um objeto Thread para evitar que o programa termine • Vamos aprender este mecanismo usando um exemplo
  • 20. Programa Exemplo 1. Primeiro, temos de implementar uma classe para tratar as exceções não verificadas. Esta classe deve implementar a interface UncaughtExceptionHandler e implementar o método uncaughtException() declarado na interface. No nosso caso, chame essa classe de ExceptionHandler e faça o método para gravar informações sobre a Exception e a Thread que a lançou. Veja o código a seguir.
  • 21. Programa Exemplo public class ExceptionHandler implements UncaughtExceptionHandler { public void uncaughtException(Thread t, Throwable e) { System.out.printf("Uma exceção foi capturadan"); System.out.printf("Thread: %sn",t.getId()); System.out.printf("Exception: %s: %sn", e.getClass().getName(),e.getMessage()); System.out.printf("Stack Trace: n"); e.printStackTrace(System.out); System.out.printf("Thread status: %sn", t.getState()); } }
  • 22. Programa Exemplo 2. Agora, implemente uma classe que gera uma exceção não verificada. Chame esta classe de Task, especifique que ela implementa a interface Runnable, implemente o método run(), e force a exceção, por exemplo, ao tentar converter um valor de sequência de caracteres em um valor int. public class Task implements Runnable { @Override public void run() { int numero=Integer.parseInt("TTT"); } }
  • 23. Programa Exemplo 3. Agora implemente a classe principal do exemplo. Implemente uma classe chamada Main com o método main(). public class Main { public static void main(String[] args) { 4. Crie um objeto do tipo Task e uma Thread para executá-lo. Defina o manipulador de exceção não verificada usando o método setUncaughtExceptionHandler() e inicie a execução da Thread. Task task=new Task(); Thread thread=new Thread(task); thread.setUncaughtExceptionHandler( new ExceptionHandler()); thread.start(); } }
  • 24. Programa Exemplo 5. Execute o exemplo e veja os resultados.
  • 25. Funcionamento • A exceção é lançada e capturado pelo manipulador que escreve no console as informações sobre a exceção e a Thread que a lançou • Quando uma exceção é lançada em uma thread e não é capturada (tem que ser uma exceção não verificada), a JVM verifica se a thread tem um manipulador de exceção não capturada definido pelo método correspondente, se tiver, a JVM invoca este método com os objetos Thread e Exception como argumentos • Se a thread não possui um manipulador de exceção não capturada, o JVM imprime o rastreamento da pilha no console e sai do programa
  • 26. Processando Exceções em Uma Thread • A classe Thread tem outro método relacionado com o processo de exceções, ele é o método estático setDefaultUncaughtExceptionHandler() que estabelece um manipulador de exceção para todos os objetos Thread da aplicação
  • 27. Processando Exceções em Uma Thread • Quando uma exceção não detectada é lançada em Thread, a JVM procura por três manipuladores possíveis para essa exceção: – Primeiro, ele busca pelo manipulador de exceção não capturada dos objetos Thread como aprendemos neste exemplo – Se o manipulador não existe, então a JVM busca pelo manipulador de exceção não capturada do ThreadGroup dos objetos Thread como veremos adiante – Se esse método não existe, a JVM busca pelo manipulador de exceção não capturada padrão – Se nenhum deles existe, a JVM imprime o rastreamento da pilha da exceção no console e sai do programa
  • 28.
  • 29. Utilizando Variáveis de Thread Locais • Um dos aspectos mais críticos de uma aplicação concorrente é o compartilhamento de dados • Isto tem uma importância especial naqueles objetos que estendem a classe Thread ou implementam a interface Runnable • Se você criar um objeto de uma classe que implementa a interface Runnable e, em seguida, iniciar vários objetos Thread usando o mesmo objeto Runnable, todos as threads compartilham os mesmos atributos • Isto significa que, se você alterar um atributo em uma thread, todas as threads serão afetados por esta mudança
  • 30. Utilizando Variáveis de Thread Locais • Às vezes, podemos estar interessados em ter um atributo que não será compartilhado entre todas as threads que executam o mesmo objeto • A API de Concorrência Java fornece um mecanismo limpo chamado de variáveis de threads locais com um desempenho muito bom • Neste exemplo, iremos desenvolver um programa que tem o problema mostrado no início e outro programa que resolve esse problema usando o mecanismo de variáveis de threads locais
  • 31. Programa Exemplo 1. Primeiro, vamos implementar um programa que tem o problema exposto anteriormente. Crie uma classe chamada UnsafeTask e especifique que ela implementa a interface Runnable. Declare um atributo java.util.Date privado. public class UnsafeTask implements Runnable{ private Date startDate; 2. Implemente o método run() do objeto UnsafeTask. Este método irá inicializar o atributo startDate, escrever o seu valor no console, esperar por um período de tempo aleatório, e novamente escrever o valor do atributo startDate.
  • 32. Programa Exemplo @Override public void run() { startDate=new Date(); System.out.printf(“Iniciando a Thread: %s : %sn",Thread.currentThread().getId(), startDate); try { TimeUnit.SECONDS.sleep((int)Math.rint( Math.random()*10)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Thread Finalizada: %s : %sn",Thread.currentThread().getId(), startDate); }
  • 33. Programa Exemplo 3. Agora, vamos implementar a classe principal desta aplicação problemática. Crie uma classe chamada Main com um método main(). Este método irá criar um objeto da classe UnsafeTask e iniciar três threads usando esse objeto, dormindo por 2 segundos entre cada thread. public class Main { public static void main(String[] args) { UnsafeTask task=new UnsafeTask(); for (int i=0; i<3; i++){ Thread thread=new Thread(task); thread.start(); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } } } }
  • 34. Programa Exemplo 4. Na captura de tela seguinte, podemos ver os resultados da execução deste programa. Cada thread tem uma hora de início diferentes, mas, quando terminam, todas têm o mesmo valor no seu atributo startDate.
  • 35. Programa Exemplo 5. Como mencionado anteriormente, iremos usar o mecanismo de variáveis de thread locais para resolver este problema. 6. Crie uma classe chamada SafeTask e especifique que ela implementa a interface Runnable. public class SafeTask implements Runnable { 7. Declare um objeto da classe ThreadLocal<Date>. Este objeto possuirá uma implementação implícita que inclui o método initialValue(). Este método irá retornar a data atual. private static ThreadLocal<Date> startDate= new ThreadLocal<Date>() { protected Date initialValue(){ return new Date(); } };
  • 36. Programa Exemplo 8. Implemente o método run(). Este possui a mesma funcionalidade do método run() de UnsafeClass, mas modifica a maneira como acessa o atributo startDate. @Override public void run() { System.out.printf("Iniciando Thread: %s : %sn",Thread.currentThread().getId(), startDate.get()); try { TimeUnit.SECONDS.sleep((int)Math.rint( Math.random()*10)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Thread Finalizada: %s : %sn",Thread.currentThread().getId(), startDate.get()); }
  • 37. Programa Exemplo 9. A classe principal deste exemplo é a mesma que a do exemplo inseguro, mudando o nome da classe Runnable. 10. Execute o exemplo e analise a diferença.
  • 38. Funcionamento • Agora, os três objetos Thread têm o seu próprio valor do atributo startDate • As variáveis de thread locais armazenam um valor de um atributo para cada Thread que usa uma destas variáveis • Podemos ler o valor usando o método get() e alterar o valor usando o método set() • A primeira vez que acessamos o valor de uma variável de thread local, se ela não tem nenhum valor para o objeto Thread que está chamando, a variável de thread local chama o método initialValue() para atribuir um valor para essa Thread e retorna o valor inicial
  • 39. Utilizando Variáveis de Thread Locais • A classe de thread local também fornece o método remove(), que exclui o valor armazenado na variável de thread local para a thread que está chamando • A API de Concorrência Java inclui a classe InheritableThreadLocal que fornece herança de valores para threads criadas a partir de outra thread • Se uma thread A tem um valor em uma variável de thread local e criamos outra thread B, a thread B terá o mesmo valor que a thread A na variável de thread local • Podemos sobrescrever o método childValue() que é chamado para inicializar o valor da thread filha na variável de thread local, ele recebe o valor da thread pai na variável de thread local como parâmetro
  • 40.
  • 41. Agrupando Threads • Uma funcionalidade interessante oferecida pela API de Concorrência Java é a capacidade de agrupar as threads • Isto permite-nos tratar as threads de um grupo como uma unidade, proporcionando acesso aos objetos Thread que pertencem a um grupo e realizar uma operação com elas • Por exemplo, temos algumas threads que fazem a mesma tarefa e queremos controlá-las, independentemente de quantas threads ainda estão em execução, o estado de cada uma irá interromper todas elas com uma única chamada
  • 42. Agrupando Threads • Java fornece a classe ThreadGroup para trabalhar com grupos de threads • Um objeto ThreadGroup pode ser formado por objetos Thread e por outro objeto ThreadGroup, gerando uma estrutura de árvore de threads • Neste exemplo, trabalharemos com objetos ThreadGroup desenvolvendo um exemplo simples: teremos 10 threads dormindo durante um período de tempo aleatório (simulando uma busca, por exemplo) e, quando um deles acabar, iremos interromper o resto
  • 43. Programa Exemplo 1. Primeiro, crie uma classe chamada Result. Ele irá armazenar o nome da Thread que termina em primeiro lugar. Declare um atributo privado String chamado name e os métodos para ler e definir o valor. 2. Crie uma classe chamada SeachTask e especifique que ela implementa a interface Runnable. public class SearchTask implements Runnable { 3. Declare um atributo privado da classe Result e implemente o construtor da classe que inicializa este atributo. private Result result; public SearchTask(Result result) { this.result=result; }
  • 44. Programa Exemplo 4. Implemente o método run(). Ele vai chamar o método doTask() e esperar que ele termine ou por uma exceção InterruptedException. O método gravará mensagens para indicar o início, fim ou interrupção desta Thread. @Override public void run() { ...
  • 45. Programa Exemplo @Override public void run() { String name=Thread.currentThread().getName(); System.out.printf("Thread %s: Iniciadan",name); try { doTask(); result.setName(name); } catch (InterruptedException e) { System.out.printf("Thread %s: Interrompidan",name); return; } System.out.printf("Thread %s: Terminadan",name); }
  • 46. Programa Exemplo 5. Implemente o método doTask(). Ele irá criar um objeto Random para gerar um número aleatório e chamará o método sleep() com o número gerado. private void doTask() throws InterruptedException { Random random=new Random((new Date()) .getTime()); int value=(int)(random.nextDouble()*100); System.out.printf("Thread %s: %dn", Thread.currentThread().getName(), value); TimeUnit.SECONDS.sleep(value); }
  • 47. Programa Exemplo 6. Agora crie a classe principal do exemplo e implemente o método main(). public class Main { public static void main(String[] args) { 7. Primeiro, crie um objeto ThreadGroup e o chame de Searcher. ThreadGroup threadGroup = new ThreadGroup("Searcher"); 8. Então, crie um objeto SearchTask e um objeto Result. Result result=new Result(); SearchTask searchTask = new SearchTask(result);
  • 48. Programa Exemplo 9. Agora, crie 10 objetos Thread usando o objeto SearchTask. Quando você chamar o construtor da classe Thread, passe como primeiro argumento o objeto ThreadGroup. for (int i=0; i<10; i++) { Thread thread=new Thread(threadGroup, searchTask); thread.start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } }
  • 49. Programa Exemplo 10. Imprima informação sobre o objeto ThreadGroup usando o método list(). System.out.printf("Número de Threads: %dn", threadGroup.activeCount()); System.out.printf("Informação sobre o Grupo de Threadsn"); threadGroup.list();
  • 50. Programa Exemplo 11. Use os métodos activeCount() e enumerate() para saber quantos objetos Thread estão associados ao objeto ThreadGroup e obter uma lista deles. Podemos usar esse método para obter, por exemplo, o estado de cada Thread. Thread[] threads=new Thread[threadGroup.activeCount()]; threadGroup.enumerate(threads); for (int i=0; i<threadGroup.activeCount(); i++) { System.out.printf("Thread %s: %sn", threads[i].getName(), threads[i].getState()); }
  • 51. Programa Exemplo 12. Chame o método waitFinish(). Iremos implementá-lo adiante. Ele irá esperar até que uma das threads do objeto ThreadGroup termine. waitFinish(threadGroup); 13. Interrompa o restante das threads do grupo usando o método interrupt(). threadGroup.interrupt();
  • 52. Programa Exemplo 14. Implemente o método waitFinish(). Ele irá usar o método activeCount() para controlar o final de uma das threads. private static void waitFinish(ThreadGroup threadGroup) { while (threadGroup.activeCount()>9) { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } }
  • 53. Programa Exemplo 15. Execute o exemplo e veja o resultado.
  • 54. Programa Exemplo 15. Execute o exemplo e veja o resultado.
  • 55. Programa Exemplo 15. Execute o exemplo e veja o resultado.
  • 56. Funcionamento • Na captura de tela, podemos ver a saída do método list() e a saída gerada quando escrevemos o estado de cada objeto Thread • A classe ThreadGroup armazena os objetos Thread e outros objetos ThreadGroup associados a ela, de modo que ela pode acessar todas as suas informações (estado, por exemplo) e executar operações sobre todos os seus membros (interromper, por exemplo) • A classe ThreadGroup possiu mais métodos, verifique a documentação da API para ter uma explicação completa de todos esses métodos
  • 57.
  • 58. Processando Exceções em Um Grupo de Threads • Um aspecto muito importante em toda linguagem de programação é o mecanismo que fornece gerenciamento de situações de erro na aplicação • A linguagem Java, como quase todas as linguagens de programação modernas, implementa um mecanismo baseado em exceção para gerir situações de erro • Ela fornece uma série de classes para representar erros diferentes • Essas exceções são lançadas pelas classes Java quando uma situação de erro é detectada • Podemos usar essas exceções, ou implementar nossas próprias exceções, para gerenciar os erros produzidos em nossas classes
  • 59. Processando Exceções em Um Grupo de Threads • Java também fornece um mecanismo para capturar e processar essas exceções • Há exceções que devem ser capturados ou re-lançadas usando a cláusula throws de um método, essas exceções são chamados de exceções verificadas • Há exceções que não têm de ser especificadas ou capturados, estas são as exceções não verificadas • No tópico, Controlando a Interrupção de uma Thread, vimos como usar um método genérico para processar todas as exceções não verificadas que são lançadas em um objeto Thread • Outra possibilidade é estabelecer um método que captura todas as exceções não capturadas, lançadas por qualquer Thread da classe ThreadGroup
  • 60. Programa Exemplo 1. Em primeiro lugar, temos de estender a classe ThreadGroup criando uma classe chamada MyThreadGroup. Temos de declarar um construtor com um parâmetro, porque a classe ThreadGroup não tem um construtor sem ele. public class MyThreadGroup extends ThreadGroup { public MyThreadGroup(String name) { super(name); }
  • 61. Programa Exemplo 2. Substitua o método uncaughtException(). Este método é chamado quando uma exceção é lançada em uma das threads da classe ThreadGroup. Neste caso, este método irá escrever no console informações sobre a exceção e da Thread que a lança, e interromper o restante das threads na classe ThreadGroup. @Override public void uncaughtException(Thread t, Throwable e) { System.out.printf("A thread %s lançou uma Exceçãon",t.getId()); e.printStackTrace(System.out); System.out.printf("Terminando o restante das Threadsn"); interrupt(); }
  • 62. Programa Exemplo 3. Crie uma classe chamada Task e especifique que ele implementa a interface Runnable. public class Task implements Runnable { 4. Implemente o método run(). Neste caso, vamos provocar uma exceção AritmethicException. Para isso, vamos dividir 1.000 entre números aleatórios até que o gerador random gere um zero e a exceção seja lançada. @Override public void run() { ...
  • 63. Programa Exemplo @Override public void run() { int result; Random random=new Random(Thread.currentThread() .getId()); while (true) { result=1000/((int)(random.nextDouble() *1000)); System.out.printf("%s : %dn", Thread .currentThread().getId(),result); if (Thread.currentThread().isInterrupted()) { System.out.printf("%d : Interrompidan",Thread. currentThread().getId()); return; } } }
  • 64. Programa Exemplo 5. Agora, vamos implementar a classe principal do exemplo e o método main(). public class Main { public static void main(String[] args) { 6. Crie um objeto da classe MyThreadGroup. MyThreadGroup threadGroup=new MyThreadGroup("MyThreadGroup"); 7. Crie um objeto da classe Task. Task task=new Task();
  • 65. Programa Exemplo 8. Crie dois objetos Thread com esta Task e inicie-os. for (int i=0; i<2; i++){ Thread t=new Thread(threadGroup,task); t.start(); } 9. Execute o exemplo e veja os resultados.
  • 66. Funcionamento • Quando executamos o exemplo, vemos como um dos objetos Thread lança a exceção e o outro é interrompido • Quando uma exceção não detectada é lançada em Thread, a JVM procura três possíveis manipuladores para essa exceção: – Primeiro, ela busca pelo manipulador de exceção não capturada da thread, como foi explicado em tópico anterior – Se o manipulador não existe, então a JVM busca pelo manipulador de exceção não capturada da classe ThreadGroup da thread, como vimos neste exemplo – Se esse método não existe, a JVM busca pelo manipulador de exceção não capturada padrão • Se nenhum dos manipuladores existir, a JVM escreve o rastreamento da pilha de exceção no console e sai do programa
  • 67.
  • 68. Criando Threads Através de Uma Fábrica • O padrão fábrica de objetos é um dos design patterns mais utilizados no mundo da programação orientada a objetos • É um padrão criacional e seu objetivo é desenvolver um objeto cuja missão será a criação de outros objetos de uma ou de várias classes • Então, quando nós queremos criar um objeto de uma dessas classes, usamos a fábrica em vez de usar o operador new • Com esta fábrica, nós centralizamos a criação de objetos com algumas vantagens: – É fácil alterar a classe dos objetos criados ou a forma como criar esses objetos – É fácil limitar a criação de objetos para recursos limitados, por exemplo, nós só podemos ter n objetos de um tipo – É fácil gerar dados estatísticos sobre a criação dos objetos
  • 69. Criando Threads Através de Uma Fábrica • Java fornece uma interface, a interface ThreadFactory para implementar uma fábrica de objetos Thread • Alguns utilitários avançados da API de concorrência Java usam fábricas de threads para criar threads • Neste exemplo, vamos implementar uma interface ThreadFactory para criar objetos Thread com um nome personalizado, enquanto iremos salvar as estatísticas dos objetos Thread criados
  • 70. Programa Exemplo 1. Crie uma classe chamada MyThreadFactory e especifique que ele implementa a interface ThreadFactory. public class MyThreadFactory implements ThreadFactory 2. Declare três atributos: um número inteiro chamado de counter, que vamos usar para armazenar o número do objeto Thread criado, uma String denominada name com o nome base de cada Thread criada, e uma lista (List) de objetos String chamada stats para salvar os dados estatísticos sobre os objetos Thread criados. Devemos também implementar o construtor da classe que inicializa esses atributos.
  • 71. Programa Exemplo private int counter; private String name; private List<String> stats; public MyThreadFactory(String name){ counter=0; this.name=name; stats=new ArrayList<String>(); }
  • 72. Programa Exemplo 3. Implementar o método newThread(). Este método irá receber uma interface Runnable e retorna um objeto Thread para esta interface Runnable. No nosso caso, nós geramos o nome do objeto Thread, criamos o novo objeto Thread, e salvamos as estatísticas. @Override public Thread newThread(Runnable r) { Thread t=new Thread(r,name+"-Thread_" +counter); counter++; stats.add(String.format("Thread %d criada com o nome %s em %sn",t.getId(), t.getName(),new Date())); return t; }
  • 73. Programa Exemplo 4. Implemente o método getStatistics() que retorna um objeto String com os dados estatísticos de todos os objetos Thread criados. public String getStats(){ StringBuffer buffer=new StringBuffer(); Iterator<String> it = stats.iterator(); while (it.hasNext()) { buffer.append(it.next()); } return buffer.toString(); }
  • 74. Programa Exemplo 5. Crie uma classe chamada Task e especifique que ela implementa a interface Runnable. Neste exemplo, essas tarefas não vão fazer nada além que dormir por um segundo. public class Task implements Runnable { @Override public void run() { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } }
  • 75. Programa Exemplo 6. Crie a classe principal do exemplo e implemente o método main(). public class Main { public static void main(String[] args) { 7. Crie um objeto MyThreadFactory e um objeto Task. MyThreadFactory factory=new MyThreadFactory("MyThreadFactory"); Task task=new Task(); 8. Crie 10 objetos Thread usando o objeto MyThreadFactory e os inicie. Thread thread; System.out.printf("Iniciando as Threadsn"); for (int i=0; i<10; i++){ thread=factory.newThread(task); thread.start(); }
  • 76. Programa Exemplo 9. Escreva no console as estatísticas da fabrica de threads. System.out.printf("Estatísticas:n"); System.out.printf("%sn",factory.getStats()); 10. Execute o exemplo e veja os resultados.
  • 77. Funcionamento • A interface ThreadFactory tem apenas um método chamado newThread • Ele recebe um objeto Runnable como parâmetro e retorna um objeto Thread • Quando implementamos uma interface ThreadFactory, temos que implementar essa interface e substituir esse método • A maioria das ThreadFactory básicas, têm apenas uma única linha: return new Thread(r);
  • 78. Funcionamento • Podemos melhorar esta aplicação, adicionando algumas variantes: – Criando threads personalizadas, como no exemplo, usando um formato especial para o nome ou até mesmo criando nossa própria classe Thread que herda da classe Thread Java – Salvando estatísticas de criação de threads, como mostrado no exemplo anterior – Limitando o número de threads criadas – Validando a criação das threads – E mais o que possamos imaginar • O uso do padrão de design de fábrica é uma boa prática de programação, mas, se implementarmos uma interface ThreadFactory para centralizar a criação de threads, temos que rever o código para garantir que todas as threads são criadas usando essa fábrica
  • 79. UNIVERSIDADE ESTADUAL DO SUDOESTE DA BAHIA CURSO DE CIÊNCIA DA COMPUTAÇÃO PROGRAMAÇÃO CONCORRENTE – 2015.1 Fábio M. Pereira (fabio.mpereira@uesb.edu.br)