Sie sind auf Seite 1von 68

Tecnologias Java

Threads

Marcio Seiji Oyamada


msoyamada@gmail.com
Ps-graduao
Especializao em Desenvolvimento de Software e Novas Tecnologias

Contedo programtico

Apresentao da plataforma Java


Threads
Construo de ambientes grficos
Acesso a base de dados
Sockets
RMI
Applets
Linguagem de script (JavaFX)

Threads
nica linha de execuo x mltiplas linhas de
execuo

Benefcios

Tempo de resposta
Compartilhamento de recursos
Economia de recursos
Desempenho em arquiteturas multiprocessadas

Muitos para um
Vrias threads no nvel do usurio, mapeadas
para uma nica thread no nvel do kernel
Exemplos:
Solaris Green Threads
GNU Portable Threads

Um para um
Cada thread no nvel do usurio mapeada
para uma thread no nvel do kernel
Exemplos
Windows NT/XP/2000
Linux
Solaris 9 e verses posteriores

Threads em Java
Gerenciada pela JVM
Mapeamento para o sistema operacional depende
da implementao da JVM
Java Threads
Classe Thread ou
Interface Runnable

Interface Runnable
Mtodo necessrio para descrever uma thread
public interface java.lang.Runnable {
// Methods
public abstract void run();

Exemplo:
class ThreadInterface implements Runnable{
public void run(){
for (int i=0; i <20;i++){
System.out.println("Thread["+Thread.currentThread().
getName()+"]="+i);
}

}
}

Classe Thread
Classe principal que representa uma thread em
Java
Mtodos para gerenciar threads

Obter nome da thread


Alterar a prioridade
Interromper uma thread
Liberar o processador

Criando uma thread com a classe


Thread
public class ThreadClasse extends Thread {
public ThreadClasse(){
super();
}
public void run(){

for (int i=0; i <20;i++){


System.out.println("Thread["+
Thread.currentThread().getName()+
"]="+i);
}
}
}

Executando threads (Interface


Runnable)
Utilizando a interface Runnable
public class ExecutaThread {
public static void main(String args[]) throws
InterruptedException{
Thread t1;
Thread t2;
t1= new Thread(new ThreadInterface());
t2= new Thread(new ThreadInterface());
t1.start(); // inicia a execuo da Thread
t2.start(); // inicia a execuo da Thread
System.out.println(Thread inicializadas);
t1.join();
// Aguarda a thread t1 finalizar
t2.join();
// Aguarda a thread t1 finalizar
System.out.println(Thread finalizadas);
}
}

Executando threads (Classe


Thread)
Utilizando a Classe Thread
public class ExecutaThread {
public static void main(String[] args) throws
InterruptedException {
// TODO code application logic here
ClasseThread t1= new ClasseThread();
ClasseThread t2= new ClasseThread();
t1.start();
t2.start();
System.out.println("Thread inicializadas");
t1.join();
t2.join();
System.out.println("Thread finalizadas");
}
}

Executors
Gerencia um conjunto de Threads
FixedThreadPool: nmero fixo de threads
CachedThreadPool: aloca dinamicamente

FixedThreadPool
Evita o overhead com a criao de thread
Maior controle dos recursos utilizados durante a
execuo do sistema

Exemplo Executors (1)


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
// TODO code application logic here
ExecutorService executor=
Executors.newCachedThreadPool();
for (int i=0; i < 5; i++){
executor.execute(new ThreadInterface());
}
System.out.println("Threads executando");
executor.shutdown();
}
}

Exemplo: Executors (2)


public class ThreadInterface implements Runnable{
public void run() {
for (int i=0; i <20;i++){
System.out.println("Thread["+Thread.currentThr
ead().getName()+"]="+i);
}
}
}

Executors
Mtodos
Execute(Interface Runnable): submete uma nova
interface para ser executada
Shutdown(): previne que outras threads sejam
submetidas ao ExecutorService
ShutdownNow(): tentar finalizar a execuo das
Threads

Interrompendo Threads
public class MainInterruptTest {
public static void main(String[] args) throws InterruptedException {
ExecutorService executor= Executors.newCachedThreadPool();
for (int i=0; i < 10; i++)
executor.execute(new MyThread());
System.out.println("Sleeping....");
TimeUnit.SECONDS.sleep(10);
executor.shutdownNow();
System.out.println("Shutdown solicitado");
}
}
class MyThread implements Runnable{
public void run() {
boolean sair=false;
while (!sair){
System.out.println(Thread.currentThread().getName());
if (Thread.currentThread().isInterrupted()){
System.out.println("Interrupo solicitada, finalizando a
Thread"+ Thread.currentThread().getName());
sair= true;
}
}
}
}

Thread.yield()
Para a execuo da Thread atual e libera o
processador para que uma outra Thread possa
executar
Forar a troca de contexto e conseqentemente uma melhor
distribuio do processador
public class ThreadInterface implements Runnable{
public void run() {
for (int i=0; i <10;i++){
System.out.println("Thread["+Thread.currentThread().
getName()+"]="+i);
Thread.yield();
}
}
}

Threads:Sleep
public class SleepingTest implements Runnable {
public void run() {
try {
for (int i=0; i <10; i++) {
System.out.print(Sleep
+Thread.currentThread().getName()) ;
// Old-style: // Thread.sleep(100);
// Java SE5/6-style:
TimeUnit.MILLISECONDS.sleep(100);
}
} catch(InterruptedException e) {
System.err.println("Interrupted");
}
}

public static void main(String[] args) {


ExecutorService exec = Executors.newCachedThreadPool()
for (int i = 0; i < 5; i++)
exec.execute(new SleepingTest());
exec.shutdown();
}
}

Inicializao de atributos
public class SleepingTest implements Runnable{
boolean setYield= false;
public SleepingTest (boolean _setYield){
this.setYield= _setYield;
}
public void run() {
for (int i=0; i <10;i++){
System.out.println("Thread["+Thread.currentThread().getNam
e()+"]="+i);
if (setYield)
Thread.yield();
}
}
public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool()
exec.execute(new SleepingTest(true));
exec.execute(new SleepingTest(true));
exec.execute(new SleepingTest(false));
exec.execute(new SleepingTest(false));
exec.shutdown();
}
}

Exerccios
1) Qual o comportamento na execuo das
Threads utilizando o mtodo yield()?
2) Faa uma aplicao multithread onde cada
Thread escreva na tela N vezes uma String.
O valor N e a String sero passados como
parmetro pelo construtor

Threads: Retornando valores


A interface Runnable no define um mtodo
para retornar valores
Soluo 1: utilizar a interface Callable
Soluo 2: retornar os valores em um objeto
compartilhado
Problemas de sincronizao em dados compartilhados
(veremos mais adiante)

Adotemos a soluo 1...

Interface Callable
Callable: generic possibilitando definir o tipo
de retorno
Mtodo call: ponto de entrada para a Thread
(ao invs do mtodo run()), retornando o tipo
definido no generic Callable

Exemplo: Callable(1)
public class ThreadCallable implements
Callable<int>{
private static Random generator= new Random();
public int call(){
return generator.nextInt(1000);
}
}

Exemplo: Callable(2)
import
import
import
import
import

java.util.concurrent.ExecutionException;
java.util.concurrent.ExecutorService;
java.util.concurrent.Executors;
java.util.concurrent.Future;
java.util.ArrayList;

public class MainCallable {


public static void main(String[] args) {
ExecutorService executor= Executors.newCachedThreadPool();
ArrayList<Future<Integer>> resultados= new ArrayList<Future<Integer>>();
for (int i=0; i < 10; i++)
resultados.add(executor.submit(new ThreadCallable()));
executor.shutdown();
for (int i=0; i< resultados.size(); i++){
try {
Future<Integer> result;
result = resultados.get(i);
System.out.println(result.get());
} catch (InterruptedException ex) {
ex.printStackTrace();
} catch (ExecutionException ex) {
ex.printStackTrace();
}
}
}
}

Exerccio
Faa uma aplicao Java multithread para
buscar um dado elemento em um vetor
(desordenado). Utilize um objeto Random para
gerar numeros aleatrios
Cada Thread ficar responsvel pela busca em uma
parte do vetor
Retorne a posio do elemento no vetor ou 1 caso
o elemento no foi encontrado

ThreadFactory
Um Executor utiliza padro de projeto Factory
para criar as Threads
O desenvolvedor pode criar sua prpria
ThreadFactory para criar threads
Definir atributos especficos
Definir prioridades durante a criao de threads
Definir manipuladores de exceo

ThreadFactory(1)
import java.util.concurrent.*;
public class MyThreadFactory implements ThreadFactory{
private static int count;
public MyThreadFactory(){
count=0;
}
public Thread newThread(Runnable r) {
Thread t= null;
t = new Thread(r);
count++;
t.setName("MinhaThread[" + count + "]");
return t;
}
}

ThreadFactory(2)
Classe MyThread
public class MyThread implements Runnable {
public void run() {
System.out.print(Thread.currentThread().getName());
System.out.println(Thread.currentThread().getId());
}
}
---Classe principal
import java.util.concurrent.*;
public class MainTreadFactory {
public static void main(String[] args) {
ExecutorService executor=
Executors.newFixedThreadPool(10, new MyThreadFactory());
for (int i=0; i < 10; i++)
executor.execute(new MyThread());
executor.shutdown();
}
}

Exerccio
No exerccio anterior, foi utilizado um
gerenciador de Threads com nmero fixo.
Substitua por um gerenciador dinmico
(Executors.newCachedThreadPool(new
MyFactoryThread())
Existe alguma diferena na sada gerada?

Tratando exception
import java.util.concurrent.*;
public class ExceptionThread implements Runnable {
public void run() {
throw new RuntimeException();
}
public static void main(String [] args) {
ExecutorService exec = Executors.newCachedThreadPool() ;
exec.execute(new ExceptionThread());
exec.shutdown();
}
}

Tratando internamente
import java.util.concurrent.*;
public class ExceptionThread implements Runnable {
public void run() {
try {
throw new RuntimeException();
catch (Exception ex){
ex.printStackTrace();
}
}
public static void main(String [] args) {
ExecutorService exec = Executors.newCachedThreadPool() ;
exec.execute(new ExceptionThread());
exec.shutdown();
}
}

Tratando exception(2)
/ / : concurrency/NaiveExceptionHandling.java
import java.util.concurrent.*;
public class NaiveExceptionHandling {
public static void main(String[] args) {
try {
ExecutorService exec= Executors.newCachedThreadPool();
exec.execute(new ExceptionThread()) ;
exec.shutdown();
} catch(RuntimeException ue) {
// Esse cdigo no executar!!
System.out.println("Exception has been handled!");
}
}
}

Registrando um tratador de
excees
Como pegar excees que no so tratadas
internamente nas Threads?
Registrar um tratador de excees durante a
criao de uma thread (ThreadFactory)
Interface Thread.UncaughtExceptionHandler
public void uncaughtException(Thread t,
Throwable e)

Tratador de excees(1)
public class MyThreadFactory implements ThreadFactory{
public Thread newThread(Runnable arg0) {
Thread t=new Thread(arg0);
t.setUncaughtExceptionHandler(new TrataException());
return t;
}
}

class TrataException implements UncaughtExceptionHandler{


public void uncaughtException(Thread arg0, Throwable arg1) {
System.out.println("Tratador da exceo da Thread");
}
}

Tratador de excees(2)
class MyThread implements Runnable{
public void run(){
throw new RuntimeException();
}
}
public class MainUncaughtException {
public static void main(String[] args) {
ExecutorService executor=
Executors.newCachedThreadPool(new
MyThreadFactory());
for (int i=0; i < 5 ; i++)
executor.execute(new MyThread());
}
}

Sincronizao entre threads


Acesso a variveis compartilhadas

Sincronizao
Programa concorrente
Executado por diversos processos
Acesso concorrente a dados

Paralelismo real x Paralelismo aparente


Multiprocessadores: paralelismo real
Paralelismo aparente: concorrncia

Programas concorrentes
Processos seqenciais que executam
concorrentemente (afetam ou so afetados por
outros programas)
Motivao
Aumento de desempenho em mquinas
multiprocessadas
Interface com o usurio
Sobreposio de operaes de E/S e
processamento

Problema produtor-consumidor
Seja um buffer compartilhado entre dois
processos/threads. O processo produtor coloca dados
em um buffer que so retirados pelo processo
consumidor
Possvel implementao
Uma varivel count armazena o nmero de posies
preenchidas no buffer
Inicialmente armazena o valor 0
Quando o processo produtor coloca um dado no buffer,
count incrementado
Quando o processo consumidor retira o dado do buffer,
count decrementado

Produtor
while (true) {
/* produce an item and put in nextProduced */
while (count == BUFFER_SIZE)
; // do nothing
buffer [in] = nextProduced;
in = (in + 1) % BUFFER_SIZE;
count++;
}

Consumidor
while (true) {
while (count == 0)
; // do nothing
nextConsumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
count--;
/* consume the item in nextConsumed
}

Condio de corrida
count++ ou count
register= count
register= count+1
count= register
Considere a execuo intercalada com count = 5
inicialmente:
S0: produtor executa register1 = count {register1 = 5}
S1: produtor executa register1 = register1 + 1 {register1 = 6}
S2: consumidor executa register2 = count {register2 = 5}
S3: consumidor executa register2 = register2 - 1 {register2 = 4}
S4: produtor executa count = register1 {count = 6 }
S5: consumidor executa count = register2 {count = 4}

Problema da seo crtica


Condio de corrida: vrios processos/thread
manipulam conjuntos de dados onde o
resultado depende da ordem de execuo
Seo crtica: trecho de cdigo onde somente
um processo pode executar por vez

Soluo
Criar um protocolo que garanta a excluso
mtua
Execuo da seo crtica por somente um
processo/thread

Propriedades da seo crtica


Regra 1: Excluso mtua
Regra 2: Progresso
Nenhum processo fora da seo crtica pode
bloquear um outro processo

Regra 3: Espera limitada


Nenhum processo pode esperar infinitamente para
entrar na seo crtica

Regra 4
Nenhuma considerao sobre o nmero de
processadores ou velocidades relativas

Acesso concorrente a dados

Classe Conta
public class Conta {
int saldoPoupanca;
int saldoCC;
public Conta(int _saldoPoupanca, int _saldoCC){
saldoPoupanca= _saldoPoupanca;
saldoCC= _saldoCC;
}
public void transferePoupanca(int v){
saldoCC -= v;
saldoPoupanca +=v;
}
public void transfereCC(int v){
saldoPoupanca -=v;
saldoCC +=v;
}
public int saldoTotal(){
return (saldoPoupanca + saldoCC);
}
}

Produtor
public class Produtor implements Runnable{
private Conta c;
private Random r= new Random();
public Produtor(Conta _c){
c= _c;
}
public void run(){
while (true){
c.transfereCC(r.nextInt(1000));
c.transferePoupanca(r.nextInt(500));
}
}
}

Consumidor
public class Consumidor implements Runnable{
private Conta c;
private int saldoInicial;
public Consumidor(Conta _c, int _saldoInicial){
c= _c;
saldoInicial=_saldoInicial;
}
public void run(){
int saldo;
while (true){
saldo= c.saldoTotal();
if (saldo != saldoInicial){
System.out.println("Saldo errado = "+saldo);
Thread.currentThread().yield();
}
}
}
}

Sincronizando acessos concorrentes


Synchronized
Evita a execuo concorrente das threads

Como definir a sincronizao


Mtodos
public synchronized transfereCC(int v);
public synchronized transferePoupanca(int v);
public synchronized saldoTotal();

Quando um mtodo definido como synchronized,


ocorre um bloqueio, evitando a execuo
No mtodo
Entre mtodos synchronized da classe

Exerccio
1) Altere o cdigo da transferncia de conta
para que o mesmo funcione corretamente
2) Verifique o funcionamento da aplicao
SerialNumberGenerator
a) Identifique o problema
b) Faa as alteraes necessrias

Utilizando tipos de dados


sincronizados
AtomicInteger, AtomicLong
boolean compareAndSet(expectedValue,
updateValue);
addAndGet (int delta)
incrementAndGet()

AtomicReference<V>
boolean compareAndSet(expectedValue,
updateValue);
getAndSet(V newValue)

Tipos de dados sincronizados


Os tipos Queue (fila) LinkedQueue (lista)
no pacote java.util no so sincronizados
Tipos de dados thread-safe so definidos
no pacote java.util.concurrent
Interface BlockingQueue()
Classe: ArrayBlockingQueue
void put(E e);
E take();

ArrayBlockingQueue
class Main() {
// Instanciando
private ArrayBlockingQueue<Integer> buffer= new
ArrayBlockingQueue<Integer>(5); // buffer de 5 posies
}
// inserindo elementos no buffer
buffer.put(new Integer(5));

//removendo elementos do buffer


valor= buffer.take();

Exerccio
Implemente duas Threads, uma produtora e
uma consumidora
O Produtor dever gerar 1000 nmeros e colocar
no buffer compartilhado para ser consumido pela
Thread Consumidor
Utilize a classe BlockingQueue como buffer
compartilhado

Material complementar

Semforos

Proposto por Dijkstra(1965)


Sincronizao que no necessita de espera ativa
Semforo S varivel inteira
Duas operaes S: acquire() e release()
Operaes atmicas

Semforo
Binrio: varia entre 0 e 1
Contador: valor inteiro

Implementao de semforos
Deve garantir que dois processos no
executem acquire () e release () no mesmo
semforo ao mesmo tempo
A implementao do acquire e release tornase o problema de seo crtica.
Espera ativa

Algumas aplicaes podem ficar muito tempo


na seo crtica.

Implementao de semforo sem


espera ativa
Cada semforo tem sua fila de espera. Cada
posio da fila de espera tem dois campos:
valor (tipo inteiro)
ponteiro para o prximo elemento da lista

Duas operaes:
block coloca o processo que esta adquirindo
o semforo na fila apropriada.
wakeup remove o processo que esta na fila
de espera e coloca na fila de prontos.

Implementao de semforo sem


espera ativa
Acquire()

Release()

Semafros em Java
Exemplo:
import java.util.concurrent.Semaphore;
public class ThreadInterface implements Runnable{
Semaphore sem= new Semaphore(1);
public void run() {
sem.acquire();
for (int i=0; i <10;i++){
System.out.println("Thread["+Thread.currentThread().
getName()+"]="+i);
Thread.yield();
}
sem.release();
}
public static void main(String args[]) {
ExecutorService executor= Executors.newCachedThreadPool();
for (int i=0; i < 5; i++)
executor.execute(new MyThread());

}
}

Bloqueios e variveis de condio


Menor overhead que semforos e synchronized
Implementao mais eficiente no Java
Variveis de condio so utilizadas caso seja
necessrio bloquear a execuo no meio da
seo crtica

Exemplo: Lock
import java.util.concurrent.locks.*;
public class ThreadInterface implements Runnable{
Lock mutex= new Lock();
public void run() {
mutex.lock();
for (int i=0; i <10;i++){
System.out.println("Thread["+Thread.currentThread().
getName()+"]="+i);
Thread.yield();
}
mutex.unlock();
}
public static void main(String args[]) {
ExecutorService executor= Executors.newCachedThreadPool();
for (int i=0; i < 5; i++)
executor.execute(new MyThread());

Exemplo: Variveis de condio

class ProducerConsumer {
Lock mutex= new Lock();
Condition cond= mutex.newCondition();
static class Produtor extends Runnable{
public void run() {
while (true) {
mutex.lock();
while (count == BUFFER_SIZE)
cond.await();
buffer [in] = nextProduced;
in = (in + 1) % BUFFER_SIZE;
count++;
cond.signal();
}
}
}
static class Consumidor extends Runnable{
public void run() {
while (true) {
mutex.lock();
while (count == 0)
cond.await();
nextConsumed= buffer[out];
out = (out + 1) % BUFFER_SIZE;
count--;
cond.signal();
}
}
}
..
..// mtodo Main
}

Deadlock e starvation
Deadlock dois ou mais processsos esperam infinitamente por eventos que
somente podem ser gerados por processos no estado de espera
Seja S e Q dois semforos inicializados em 1
P0
P1
S.acquire();
Q.acquire();
Q.acquire();
S.acquire();
.
.
.
.
.
.
S.release();
Q.release();
Q.release();
S.release();
Starvation bloqueio indefinido.

Das könnte Ihnen auch gefallen