Você está na página 1de 17

Programao Concorrente e Threads - Java e Orientao a Objetos

18/01/15 15:03

CAPTULO 17

Programao Concorrente e
Threads
"O nico lugar onde o sucesso vem antes do trabalho no
dicionrio."
Albert Einstein
Ao trmino desse captulo, voc ser capaz de:
executar tarefas simultaneamente;
colocar tarefas para aguardar at que um determinado evento
ocorra;
entender o funcionamento do Garbage Collector.

17.1 - THREADS
"Duas tarefas ao mesmo tempo"
http://www.caelum.com.br/apostila-java-orientacao-objetos/programacao-concorrente-e-threads/#17-1-threads

Pgina 1 de 17

Programao Concorrente e Threads - Java e Orientao a Objetos

18/01/15 15:03

Em vrias situaes, precisamos "rodar duas coisas ao mesmo


tempo". Imagine um programa que gera um relatrio muito
grande em PDF. um processo demorado e, para dar alguma
satisfao para o usurio, queremos mostrar uma barra de
progresso. Queremos ento gerar o PDF e ao mesmo tempo
atualizar a barrinha.
Pensando um pouco mais amplamente, quando usamos o
computador tambm fazemos vrias coisas simultaneamente:
queremos navegar na internet e ao mesmo tempo ouvir msica.
A necessidade de se fazer vrias coisas simultaneamente, ao
mesmo tempo, paralelamente, aparece frequentemente na
computao. Para vrios programas distintos, normalmente o
prprio sistema operacional gerencia isso atravs de vrios

processos em paralelo.
Em um programa s (um processo s), se queremos executar
coisas em paralelo, normalmente falamos de Threads.

Threads em Java
Em Java, usamos a classe Thread do pacote java.lang para criarmos

linhas de execuo paralelas. A classe Thread recebe como


argumento um objeto com o cdigo que desejamos rodar. Por
exemplo, no programa de PDF e barra de progresso:
public class GeraPDF {
public void rodar () {
// lgica para gerar o pdf...
}
http://www.caelum.com.br/apostila-java-orientacao-objetos/programacao-concorrente-e-threads/#17-1-threads

Pgina 2 de 17

Programao Concorrente e Threads - Java e Orientao a Objetos

18/01/15 15:03

}
public class BarraDeProgresso {
public void rodar () {
// mostra barra de progresso e vai atualizando ela...
}
}

E, no mtodo main, criamos os objetos e passamos para a classe


Thread. O mtodo start responsvel por iniciar a execuo da
Thread:
public class MeuPrograma {
public static void main (String[] args) {
GeraPDF gerapdf = new GeraPDF();
Thread threadDoPdf = new Thread(gerapdf);
threadDoPdf.start();
BarraDeProgresso barraDeProgresso = new
BarraDeProgresso();
Thread threadDaBarra = new Thread(barraDeProgresso);
threadDaBarra.start();
}
}

O cdigo acima, porm, no compilar. Como a classe Thread


sabe que deve chamar o mtodo roda? Como ela sabe que nome de
mtodo daremos e que ela deve chamar esse mtodo especial?
Falta na verdade um contrato entre as nossas classes a serem
executadas e a classe Thread.
Esse contrato existe e feito pela interface Runnable: devemos
dizer que nossa classe "executvel" e que segue esse contrato.
http://www.caelum.com.br/apostila-java-orientacao-objetos/programacao-concorrente-e-threads/#17-1-threads

Pgina 3 de 17

Programao Concorrente e Threads - Java e Orientao a Objetos

18/01/15 15:03

Na interface Runnable, h apenas um mtodo chamado run. Basta


implement-lo, "assinar" o contrato e a classe Thread j saber
executar nossa classe.
public class GeraPDF implements Runnable {
public void run () {
// lgica para gerar o pdf...
}
}
public class BarraDeProgresso implements Runnable {
public void run () {
// mostra barra de progresso e vai atualizando ela...
}
}
APOSTILA JAVA E ORIENTAO A OBJETOS

A classe Thread recebe no construtor um objeto que um

Runnable, e seu mtodo start chama o mtodo run da nossa


classe. Repare que a classe Thread no sabe qual o tipo especfico
da nossa classe; para ela, basta saber que a classe segue o contrato
estabelecido e possui o mtodo run.
o bom uso de interfaces, contratos e polimorfismo na prtica!

Estendendo a classe Thread


A classe Thread implementa Runnable. Ento, voc pode
criar uma subclasse dela e reescrever o run que, na classe
Thread, no faz nada:
public class GeraPDF extends Thread {
public void run () {
http://www.caelum.com.br/apostila-java-orientacao-objetos/programacao-concorrente-e-threads/#17-1-threads

Pgina 4 de 17

Programao Concorrente e Threads - Java e Orientao a Objetos

18/01/15 15:03

// ...
}
}

E, como nossa classe uma Thread, podemos usar o start


diretamente:
GeraPDF gera = new GeraPDF();
gera.start();

Apesar de ser um cdigo mais simples, voc est usando


herana apenas por "preguia" (herdamos um monte de
mtodos mas usamos apenas o run), e no por
polimorfismo, que seria a grande vantagem. Prefira
implementar Runnable a herdar de Thread.

Dormindo
Para que a thread atual durma basta chamar o mtodo a
seguir, por exemplo, para dormir 3 segundos:
Thread.sleep(3 * 1000);

17.2 - ESCALONADOR E TROCAS DE CONTEXTO


Veja a classe a seguir:
1

public class Programa implements Runnable {

http://www.caelum.com.br/apostila-java-orientacao-objetos/programacao-concorrente-e-threads/#17-1-threads

Pgina 5 de 17

Programao Concorrente e Threads - Java e Orientao a Objetos

18/01/15 15:03

private int id;


// colocar getter e setter pro atributo id

3
4
5

public void run () {


7
for (int i = 0; i < 10000; i++) {
8
System.out.println("Programa " + id + " valor:
" + i);
9
}
10
}
11 }
6

uma classe que implementa Runnable e, no mtodo run,


apenas imprime dez mil nmeros. Vamos us-las duas vezes para
criar duas threads e imprimir os nmeros duas vezes
simultaneamente:
1
2

public class Teste {


public static void main(String[] args) {

Programa p1 = new Programa();


p1.setId(1);

4
5
6

Thread t1 = new Thread(p1);


t1.start();

7
8
9

Programa p2 = new Programa();


p2.setId(2);

10
11
12

Thread t2 = new Thread(p2);


t2.start();

13
14
15

16
17

Se rodarmos esse programa, qual ser a sada? De um a mil e


depois de um a mil? Provavelmente no, seno seria sequencial.
http://www.caelum.com.br/apostila-java-orientacao-objetos/programacao-concorrente-e-threads/#17-1-threads

Pgina 6 de 17

Programao Concorrente e Threads - Java e Orientao a Objetos

18/01/15 15:03

Ele imprimir 0 de t1, 0 de t2, 1 de t1, 1 de t2, 2 de t1, 2 de t2 e etc?


Exatamente intercalado?
Na verdade, no sabemos exatamente qual a sada. Rode o
programa vrias vezes e observe: em cada execuo a sada um
pouco diferente.
O problema que no computador existe apenas um processador
capaz de executar coisas. E quando queremos executar vrias
coisas ao mesmo tempo, e o processador s consegue fazer uma
coisa de cada vez? Entra em cena o escalonador de threads.
O escalonador (scheduler), sabendo que apenas uma coisa pode
ser executada de cada vez, pega todas as threads que precisam ser
executadas e faz o processador ficar alternando a execuo de cada
uma delas. A ideia executar um pouco de cada thread e fazer essa
troca to rapidamente que a impresso que fica que as coisas
esto sendo feitas ao mesmo tempo.
O escalonador responsvel por escolher qual a prxima thread
a ser executada e fazer a troca de contexto (context switch). Ele
primeiro salva o estado da execuo da thread atual para depois
poder retomar a execuo da mesma. A ele restaura o estado da
thread que vai ser executada e faz o processador continuar a
execuo desta. Depois de um certo tempo, esta thread tirada do
processador, seu estado (o contexto) salvo e outra thread
colocada em execuo. A troca de contexto justamente as
operaes de salvar o contexto da thread atual e restaurar o da
thread que vai ser executada em seguida.
http://www.caelum.com.br/apostila-java-orientacao-objetos/programacao-concorrente-e-threads/#17-1-threads

Pgina 7 de 17

Programao Concorrente e Threads - Java e Orientao a Objetos

18/01/15 15:03

Quando fazer a troca de contexto, por quanto tempo a thread vai


rodar e qual vai ser a prxima thread a ser executada, so escolhas
do escalonador. Ns no controlamos essas escolhas (embora
possamos dar "dicas" ao escalonador). Por isso que nunca
sabemos ao certo a ordem em que programas paralelos so
executados.
Voc pode pensar que ruim no saber a ordem. Mas perceba
que se a ordem importa para voc, se importante que
determinada coisa seja feita antes de outra, ento no estamos
falando de execues paralelas, mas sim de um programa
sequencial normal (onde uma coisa feita depois da outra, em
uma sequncia).
Todo esse processo feito automaticamente pelo escalonador
do Java (e, mais amplamente, pelo escalonador do sistema
operacional). Para ns, programadores das threads, como se as
coisas estivessem sendo executadas ao mesmo tempo.

E em mais de um processador?
A VM do Java e a maioria dos SOs modernos consegue fazer
proveito de sistemas com vrios processadores ou multicore. A diferena que agora temos mais de um processador
executando coisas e teremos, sim, execues
verdadeiramente paralelas.
Mas o nmero de processos no SO e o nmero de Threads
http://www.caelum.com.br/apostila-java-orientacao-objetos/programacao-concorrente-e-threads/#17-1-threads

Pgina 8 de 17

Programao Concorrente e Threads - Java e Orientao a Objetos

18/01/15 15:03

paralelas costumam ser to grandes que, mesmo com vrios


processadores, temos as trocas de contexto. A diferena
que o escalonador tem dois ou mais processadores para
executar suas threads. Mas dificilmente ter uma mquina
com mais processadores que threads paralelas executando.

Voc no est nessa pgina a toa


Voc chegou aqui porque a Caelum referncia
nacional em cursos de Java, Ruby, Agile, Mobile,
Web e .NET.
Faa curso com quem escreveu essa apostila.
Consulte as vantagens do curso Java e Orientao a Objetos.

17.3 - GARBAGE COLLECTOR


O Garbage Collector (coletor de lixo, lixeiro) funciona como
uma Thread responsvel por jogar fora todos os objetos que no
esto sendo referenciados por nenhum outro objeto - seja de
maneira direta ou indireta.
Considere o cdigo:
Conta conta1 = new ContaCorrente();
Conta conta2 = new ContaCorrente();
http://www.caelum.com.br/apostila-java-orientacao-objetos/programacao-concorrente-e-threads/#17-1-threads

Pgina 9 de 17

Programao Concorrente e Threads - Java e Orientao a Objetos

18/01/15 15:03

At este momento, sabemos que temos 2 objetos em memria.


Aqui, o Garbage Collector no pode eliminar nenhum dos objetos,
pois ainda tem algum se referindo a eles de alguma forma.
Podemos, ento, executar uma linha que nos faa perder a
referncia para um dos dois objetos criados, como, por exemplo, o
seguinte cdigo:
conta2 = conta1;

Quantos objetos temos em memria?


Perdemos a referncia para um dos objetos que foram criados.
Esse objeto j no mais acessvel. Temos, ento, apenas um
objeto em memria? No podemos afirmar isso! Como o Garbage

Collector uma Thread, voc no tem garantia de quando ele vai


rodar. Voc s sabe que, em algum momento no futuro, aquela
memria vai ser liberada.
Algumas pessoas costumam atribuir null a uma varivel, com o
intuito de acelerar a passagem do Garbage Collector por aquele
objeto:
for (int i = 0; i < 100; i++) {
List x = new ArrayList();
// faz algumas coisas com a arraylist
x = null;
}

Isso rarissimamente necessrio. O Garbage Collector age


apenas sobre objetos, nunca sobre variveis. Nesse caso, a varivel
http://www.caelum.com.br/apostila-java-orientacao-objetos/programacao-concorrente-e-threads/#17-1-threads

Pgina 10 de 17

Programao Concorrente e Threads - Java e Orientao a Objetos

18/01/15 15:03

x no existir mais a cada iterao, deixando a ArrayList criada


sem nenhuma referncia para ela.

System.gc()
Voc nunca consegue forar o Garbage Collector, mas
chamando o mtodo esttico gc da classe System, voc est
sugerindo que a Virtual Machine rode o Garbage Collector
naquele momento. Se sua sugesto vai ser aceita ou no,
isto depende de JVM para JVM, e voc no tem garantias.
Evite o uso deste mtodo. Voc no deve basear sua
aplicao em quando o Garbage Collector vai rodar ou no.

Finalizer
A classe Object define tambm um mtodo finalize, que
voc pode reescrever. Esse mtodo ser chamado no
instante antes do Garbage Collector coletar este objeto. No
um destrutor, voc no sabe em que momento ele ser
chamado. Algumas pessoas o utilizam para liberar recursos
"caros" como conexes, threads e recursos nativos. Isso
deve ser utilizado apenas por segurana: o ideal liberar
esses recursos o mais rpido possvel, sem depender da
passagem do Garbage Collector.

http://www.caelum.com.br/apostila-java-orientacao-objetos/programacao-concorrente-e-threads/#17-1-threads

Pgina 11 de 17

Programao Concorrente e Threads - Java e Orientao a Objetos

18/01/15 15:03

17.4 - EXERCCIOS
1. Teste o exemplo deste captulo para imprimir nmeros em
paralelo.
Escreva a classe Programa:
1

public class Programa implements Runnable {

private int id;


// colocar getter e setter pro atributo id

3
4
5

public void run () {


for (int i = 0; i < 10000; i++) {
System.out.println("Programa " + id + " valor: "

6
7
8

+ i);
}

10
11

Escreva a classe de Teste:


1
2

public class Teste {


public static void main(String[] args) {

3
4
5

Programa p1 = new Programa();


p1.setId(1);

6
7
8

Thread t1 = new Thread(p1);


t1.start();

9
10
11

Programa p2 = new Programa();


p2.setId(2);

12
13
14

Thread t2 = new Thread(p2);


t2.start();

http://www.caelum.com.br/apostila-java-orientacao-objetos/programacao-concorrente-e-threads/#17-1-threads

Pgina 12 de 17

Programao Concorrente e Threads - Java e Orientao a Objetos

18/01/15 15:03

15

16
17

Rode vrias vezes a classe Teste e observe os diferentes resultados


em cada execuo. O que muda?

17.5 - E AS CLASSES ANNIMAS?


comum aparecer uma classe annima junto com uma thread.
Vimos como us-la com o Comparator. Vamos ver como usar em
um Runnable.
Considere um Runnable simples, que apenas manda imprimir
algo na sada padro:
1
2
3
4
5
6
7

public class Programa1 implements Runnable {


public void run () {
for (int i = 0; i < 10000; i++) {
System.out.println("Programa 1 valor: " + i);
}
}
}

No seu main, voc faz:


Runnable r = new Programa1();
Thread t = new Thread(r);
t.start();

Em vez de criar essa classe Programa1, podemos utilizar o


recurso de classe annima. Ela nos permite dar new numa
http://www.caelum.com.br/apostila-java-orientacao-objetos/programacao-concorrente-e-threads/#17-1-threads

Pgina 13 de 17

Programao Concorrente e Threads - Java e Orientao a Objetos

18/01/15 15:03

interface, desde que implementemos seus mtodos. Com isso,


podemos colocar diretamente no main:
Runnable r = new Runnable() {
public void run() {
for(int i = 0; i < 10000; i++)
System.out.println("programa 1 valor " + i);
}
};
Thread t = new Thread(r);
t.start();

Limitaes das classes annimas


O uso de classes annimas tem limitaes. No podemos
declarar um construtor. Como estamos instanciando uma
interface, ento no conseguimos passar um parmetro
para ela. Como ento passar o id como argumento? Voc
pode, de dentro de uma classe annima, acessar atributos da
classe dentro da qual foi declarada! Tambm pode acessar as
variveis locais do mtodo, desde que eles sejam final.

E com lambda do Java 8?


D para ir mais longe com o Java 8, utilizando o lambda. Como
Runnable uma interface funcional (contm apenas um mtodo
abstrato), ela pode ser facilmente escrita dessa forma:
Runnable r = () -> {
for(int i = 0; i < 10000; i++)
http://www.caelum.com.br/apostila-java-orientacao-objetos/programacao-concorrente-e-threads/#17-1-threads

Pgina 14 de 17

Programao Concorrente e Threads - Java e Orientao a Objetos

18/01/15 15:03

System.out.println("programa 1 valor " + i);


};
Thread t = new Thread(r);
t.start();

A sintaxe pode ser um pouco estranha. Como no h


parmetros a serem recebidos pelo mtodo run, usamos o () para
indicar isso. Vale lembrar, mais uma vez, que no lambda no
precisamos escrever o nome do mtodo que estamos
implementando, no nosso caso o run. Isso possvel pois existe
apenas um mtodo abstrato na interface.
Quer deixar o cdigo mais enxuto ainda? Podemos passar o
lambda diretamente para o construtor de Thread, sem criar uma
varivel temporria! E logo em seguida chamar o start:
new Thread(() -> {
for(int i = 0; i < 10000; i++)
System.out.println("programa 1 valor " + i);
}).start();

Obviamente o uso excessivo de lambdas e classes annimas


pode causar uma certa falta de legibilidade. Voc deve lembrar que
usamos esses recursos para escrever cdigos mais legveis, e no
apenas para poupar algumas linhas de cdigo. Caso nossa
implementao do lambda venha a ser de vrias linhas, um forte
sinal de que deveramos ter uma classe a parte somente para ela.

Seus livros de tecnologia parecem do sculo passado?


Conhea a Casa do Cdigo, uma nova editora, com autores
http://www.caelum.com.br/apostila-java-orientacao-objetos/programacao-concorrente-e-threads/#17-1-threads

Pgina 15 de 17

Programao Concorrente e Threads - Java e Orientao a Objetos

18/01/15 15:03

de destaque no mercado, foco em ebooks (PDF,


epub, mobi), preos imbatveis e assuntos
atuais.
Com a curadoria da Caelum e excelentes autores,
uma abordagem diferente para livros de tecnologia no
Brasil. Conhea os ttulos e a nova proposta, voc vai gostar.
Casa do Cdigo, livros para o programador.

CAPTULO ANTERIOR:

PRXIMO CAPTULO:

Collections framework

E agora?

Voc encontra a Caelum tambm em:

Blog
Caelum

Cursos
Online

Facebook

Newsletter

http://www.caelum.com.br/apostila-java-orientacao-objetos/programacao-concorrente-e-threads/#17-1-threads

Pgina 16 de 17

Programao Concorrente e Threads - Java e Orientao a Objetos

Casa do
Cdigo

18/01/15 15:03

Twitter

http://www.caelum.com.br/apostila-java-orientacao-objetos/programacao-concorrente-e-threads/#17-1-threads

Pgina 17 de 17

Você também pode gostar