Programação Concorrente JAVA

Preview:

DESCRIPTION

Programação Concorrente JAVA. Prof. Alexandre Monteiro Recife. Contatos. Prof. Guilherme Alexandre Monteiro Reinaldo Apelido: Alexandre Cordel E-mail/ gtalk : alexandrecordel@gmail.com greinaldo@fbv.edu.br Site: http://www.alexandrecordel.com.br/fbv Celular: (81) 9801-1878. Conteúdo. - PowerPoint PPT Presentation

Citation preview

1

Programação Concorrente JAVA

Prof. Alexandre Monteiro

Recife

Contatos

Prof. Guilherme Alexandre Monteiro Reinaldo

Apelido: Alexandre Cordel

E-mail/gtalk: alexandrecordel@gmail.com

greinaldo@fbv.edu.br

Site: http://www.alexandrecordel.com.br/fbv

Celular: (81) 9801-1878

Conteúdo

O que é

Motivação

Conceitos

Processos

Threads

Propriedades

Safety

Liveness

Threads em JAVA

Programação Concorrente[ O que é ]

“Um programa concorrente é um conjunto de programas seqüenciais comuns que são executados em um paralelismo abstrato” (M.Bem-Ari)

Programação Concorrente[ O que é ]

“Um programa concorrente especifica 2 ou mais processos que cooperam para realizar uma tarefa. Processos cooperam através de comunicação; utilizam variáveis compartilhadas ou troca de mensagens“(G. R. Andrews)

Programação Concorrente[ Motivação ]

Aproveitar hardware com múltiplos processadores

Atender a vários usuários simultaneamente

Melhorar o desempenho das aplicações

Aumentar a disponibilidade da CPU para o usuário

Objetos ativos e controle de atividades

Programas paralelos

Programação Concorrente[ Conceitos ] Paralelismo

•Processamento simultâneo físico

Concorrência

•Processamento simultâneo lógico (aparente)

•Requer entrelaçamento (interleaving) de ações

Processo

•Execução de um programa (running)

Programa Concorrente

•Vários processos que cooperam para a realização de uma tarefa ou mais tarefas

Programação Concorrente[ Conceitos ] Comunicação

•Variáveis compartilhadas•Passagem de mensagens

Sincronização•Exclusão mútua de seções críticas•Sincronização por condição

Estado de um programa concorrente•Consiste dos valores das variáveis (explícitas e implícitas)•A execução de um comando muda o estado

Ações atômicas•Transformação indivisível de estado

Programação Concorrente[ Processos ]

Um processo é um programa que está em algum estado de execução

Tem espaço de endereçamento próprio, que é mapeado pelo S.O. para memória física

Possui um fluxo de controle ou thread único

Mantém um contador de programa (PC) que indica o endereço da próxima instrução

A MMU (Memory Management Unit) traduz os endereços lógicos em endereços físicos, que normalmente não são contíguos (Memória Virtual)

Programação Concorrente[ Processos ]

Espaço de Endereçamento Lógico

Instruções

Dados Globais

Espaço de Endereçamento

Lógico de um Processo

Pilha

Heap

Programação Concorrente[ Processos ]

Tabela de Processos

•Estado do processo

•Valores dos registradores

•Arquivos abertos

•Alocação de memória

•PID (Process ID)

•UID (User ID)

•GID (Owner’s Group ID)

Programação Concorrente[ Processos ]

Estados de um processo

1. Iniciado (Start): processo criado

2. Executando (Running): Utilizando a CPU

3. Executável ou Pronto (Runnable ou Ready): Esperando para ser escalonado para usar a CPU

4. Suspenso (Suspended): Recebeu um sinal para ser suspenso

5. Bloqueado (Blocked): Esperando pela conclusão de algum serviço solicitado ao S.O.

6. Encerrado (Dead): processo morto

Programação Concorrente[ Processos ]

Executando

Suspenso

Executável

Bloqueado

Encerrado

Iniciado

Ativo

Programação Concorrente[ Threads ]

Um processo pode ter mais de uma Thread (Linha)

Cada Thread possui contador de programa e pilha próprios

Quando um processo é escalonado para ser executado, uma das Threads entra em execução

As Threads compartilham as variáveis globais do processo

Programação Concorrente[ Threads ]

Espaço de Endereçamento de um Processo

Instruções

Variáveis Globais

Pilha

Heap

Pilha

Contadorde Programa

Thread 1

Pilha

Contadorde Programa

Thread 2

Pilha

Contadorde Programa

Thread n

Programação Concorrente[ Threads ]

Vantagens sobre processos compartilhando memória

•São muito mais leves de serem criadas

•A troca de contexto é mais suave pois compartilha instruções, heap e variáveis globais

•Facilitam o compartilhamento de memória

Threads[ Ciclo de Vida ]

Criada

Pronta Executando

Esperando

Dormindo

Encerrada

Bloqueada

Operaçãode E/Siniciada

Término

4.sleep()

5.notify()5.notityAll()

Operaçãode E/Sconcluída

2.start()

Intervalo de tempo expirou

escalonada

interrompida

1.new Thread()

3.run()

6.stop()

4.wait()

Threads[ Sincronização ]

Sincronizando Threads

•Programação com múltiplas Threads requer bastante cuidado:

- Acesso / Atualização de variáveis compartilhadas- Starvation (processo nunca é executado)- Deadlock (impasse e dois ou mais processos ficam

impedidos de continuar suas execuções e ficam bloqueados)

- Acesso a estados inválidos de outros objetos

Threads[ Sincronização ] A sincronização baseia-se na idéia de que

para acessar um método sincronizado ou um entrar em um bloco sincronizado, é preciso obter (ou já ter) o lock desse objeto.

A Thread que conseguir esse lock é a única autorizada a acessar os recursos protegidos através de sincronização.

Programação Concorrente[ Propriedades ] Safety: O programa nunca entra em um estado

inconsistente Liveness: Em algum momento o programa

entra em um estado consistente Correção Parcial: Se o programa terminar, o

resultado está correto. Caso contrário, nunca pode dar o resultado correto

Término: O programa termina eventualmente Ausência de Deadlock: Nunca todos os

processos estarão bloqueados Correção Total: O programa sempre termina e

produz o resultado correto

Safety [ Introdução ]

Objetos interagindo em múltiplas Threads normalmente provocam interferência

Programas concorrentes devem possuir 2 propriedades:

•Safety: Nada de mau acontecerá durante a execução do programa.

•Liveness: Algo de bom acontecerá durante a execução do programa.

Safety [ Imutabilidade ]

Variáveis de instância constantes (final em Java)

Encapsulamento

Não requer sincronização

Classes sem estado (stateless)

•Como não há estado, não há interferência

Safety [ Sincronização ]

Um Objeto/variável sempre está pronto para sofrer modificações, mesmo quando ainda está no meio do processamento de alguma

Acesso a estados inconsistentes devem ser evitados:

•Conflitos de leitura/escrita: vários lêem enquanto um escreve

•Conflitos de escrita/escrita: vários lêem e escrevem ao mesmo tempo

Safety [ Sincronização ]

No contexto de OO, podemos ter:

•Sincronização Total- Objetos totalmente sincronizados. Podem fazer apenas uma operações por vez

•Sincronização Parcial- Parte do objeto é sincronizado. Somente métodos sincronizados são travados

Safety [ Contenção ]

Baseia-se na idéia de manter referências únicas para objetos internos isolados dos demais.

São acessados apenas através de métodos sincronizados do objeto no qual estão contidos, estando, portanto, protegidos.

Safety [ Contenção ]

•É preciso definir um protocolo que garanta a exclusividade do recurso

serviço 2serviço 0

serviço 3

serviço 1vizinho

vizinho vizinho

vizinho

null

null

null

Recurso

Liveness [ Falhas de Liveness ]

São tão sérias quanto falhas de Safety

São mais difíceis de identificar e evitar durante o projeto

Tipos de falhas

•Contenção: uma thread, apesar de estar pronta para executar, não executa porque outra tomou recursos (também conhecida como starvation ou adiamento infinito)

Liveness [ Falhas de Liveness ]

•Dormência: uma thread não pronta falha ao tentar passar para esse estado.

•Deadlock: duas ou mais threads bloqueiam-se em um ciclo vicioso enquanto tentam acessar travas sincronizadas necessárias para continuar suas atividades

•Término prematuro: uma thread é parada ou encerrada prematuramente

29

Threads JAVA

Definições Básicas

Threads são sub-procesos no sistema operacional.

É menos custoso gerenciar threads do que processos.

As linguagens Java e Ada possuem funcionalidades MULTITHREADING na própria estrutura da linguagem.

C e C++ necessitam de biblioteca especifica para processamento MULTITHREADING •Posix p_thread

Diagrama de Estados Thread JavaO diagrama mostra os estados de uma thread de Java pode estar e alguns métodos que podem ser usados para mudar de um estado para outro.

New Thread

Inicialização do thread - feita através do construtor Thread().

class MyThreadClass extends Thread{

...

}

...

MyThreadClass myThread = new MyThreadClass();

Neste estado, nenhum recurso do sistema foi alocado para o thread ainda, assim, a partir daqui, tudo que você pode fazer é um start(), para ativar o thread, ou um stop(), para "matá-lo".

A chamada de qualquer outro método não faz sentido e levantará a exceção IllegalThreadStateException.

Runnable

Este é o estado em que o thread está pronto para rodar. O método start() requisita os recursos do sistema necessários para rodar o thread e chama o seu método run().

O método run() é a "alma" de um thread; é neste método que definimos o que o thread vai executar.

Thread myThread = new MyThreadClass();

myThread.start();

Falamos em "Runnable", ao invés de "Running", porque o thread pode não estar realmente sendo executado. Imagine um computador com um único processador - seria impossível executar todos os threads "Runnable" ao mesmo tempo. O que ocorre é que a CPU deve ser escalonada entre os vários threads.

Quando um thread está "Running", ele está também "Runnable", e, as instruções do seu método run() é que estão sendo executadas pela CPU.

Not Runnable

O estado "Not Runnable" significa que o thread está impedido de executar por alguma razão. Existem 4 maneiras através das quais um thread ir para o estado "Not Runnable":

•Alguém manda-lhe a mensagem suspend().

•Alguém manda-lhe a mensagem sleep().

•O thread bloqueia, esperando por I/O.

•O thread usa seu método wait() para esperar por uma variável de condição.

Not Runnable

O exemplo abaixo coloca “myThread” para dormir por 10 segundos...

Thread myThread = new MyThreadClass();

myThread.start();

try {

myThread.sleep(10000);

} catch (InterruptedException e){

}

Not Runnable

Cada uma destas maneiras tem a sua forma específica de sair do estado "Not Runnable".

•Se o thread foi suspenso, alguém precisa mandar-lhe a mensagem resume().

•Se o thread foi posto para dormir, ele voltará a ser "Runnable" quando o número de milisegundos determinado passar.

•Se o thread está bloqueado, esperando por I/O, a I/O precisa ser completada.

•Se o thread está esperando por uma variável de condição, o objeto que a "segura" precisa liberá-la, através de um notify() ou de um notifyAll()

Dead

Um thread pode morrer de "causas naturais" (quando o seu método run() acaba normalmente) ou pode ser morto (AssAssINAdO pelo método stop()).

Thread myThread = new MyThreadClass(); myThread.start();

public void run() { int i = 0; while (i < 100) {

i++; System.out.println("i = " + i);

} }

Este thread vai morrer naturalmente quando o loop do run() acabar.

Dead

O que vai acontecer com este thread?

Thread myThread = new MyThreadClass(); myThread.start();

try { Thread.currentThread().sleep(10000);

} catch (InterruptedException e){ } myThread.stop();

Método yield()

O método yield()

Cede a CPU para outros threads

Thread em Java

Em Java, threads são implementadas como uma CLASSE

•Pacote java.lang.Thread

•É uma extensão da classe Thread

•Contrutores:- public Thread (String nome_da_thread);- public Thread ( ); // o nome sera Thread-#

• Thread-1, Thread-2,…

Principais Métodos

•run(): é o método que executa as atividades de uma THREAD. Quando este método finaliza, a THREAD também termina.

•start(): método que dispara a execução de uma THREAD. Este método chama o método run( ) antes de terminar.

•sleep(int x): método que coloca a THREAD para dormir por x milisegundos.

Principais Métodos

•join( ): método que espera o término da THREAD para qual foi enviada a mensagem para ser liberada.

•interrupt( ): método que interrompe a execução de uma THREAD.

•interrupted( ): método que testa se uma THREAD está ou não interrompida.

Estados de uma Thread em Java

nascimento

pronta

executando

esperando dormindo mortabloqueada

start( )

Alocar um processador

wait( )sleep( )

Fim do Método run( )

E/S

Fim da E/Snotify( )

notifyAll( )

Término do tempo de dormida

run( )

stop( )

Prioridade de Thread

Em Java, a prioridade é determinada com um inteiro entre 1 e 10.

A prioridade padrão é o valor 5.

10 é a maior prioridade e 1 é a menor.

A THREAD herda a prioridade da THREAD que acriou.

void setPriority(int prioridade);

int getPriority( );

Algoritmo de Escalonamento

Prioridade 10

Prioridade 1

Prioridade 9

Prioridade 8

Prioridade 2

Prioridade 3

.

.

.

A B

C

D E F

G

Exercício 01

O programa cria 04 threads e as coloca para dormir.

ThreadBasica é uma extensão da classe Thread.

Exercício 01

•Analise como se chama o método sleep().

•Crie n THREADs, onde n é definido pelo usuário.

•Utilize o método join no main para esperar as THREADs terminarem. try { uma_thread.join( ); // uma_thread.join(tempo)

… }catch (InterruptedException e) {

… }

Escalonamento de Threads

Prioridade 10

Prioridade 1

Prioridade 9

Prioridade 8

Prioridade 2

Prioridade 3

.

.

.

A B

C

D E F

G

Exercício 02

Prioridades de Threads

Utilize o método setPriority(int) para mudar a prioridade de threads

•Utilize 01 thread com prioridade 1, 01 com prioridade 09 e as outras com prioridade 05.

•Faça com que uma das threads de alta prioridade durma por 10 ms antes de terminar.

•Faça com que outra thread de alta prioridade faça uma entrada de dado.

Exercício 03

Problema Produtor X Consumidor

- Com buffer de tamanho 1.

- Variáveis compartilhadas.

- A solução do problema seria utilizar-se duas THREADS: 01 consumidor e 01 produtor.

- O que ocorre se não houver sincronização entre a leitura e escrita?

Exercício 04

Problema do Produtor X Consumidor com sincronização do Buffer.

Em Java, a sincronização entre threads é feita através do conceito de monitores.

Monitor é um agrupamento de funções, cujas execuções não podem se dar de forma concorrente.

Exercício 04

Utilizar os métodos multuamente excludentes de um objeto como do tipo synchronized em Java.

Utilizar os métodos wait( ) e notify( ) para bloquear e liberar, respectivamente, as threads.

Resolver o problema de Produtor-Consumidor.

A interface Runnable

A solução encontrada em Java foi a utilização de uma interface: Runnable

•No caso, tem-se de implementar esta interface, que possui o método run( ).

public class Filho extends Pai implements Runnable

•Ao implementar uma interface, a classe se capacita a ser tratada como se fosse um objeto do tipo da inteface implementada.

- Se a classe Filho implementar a interface Runnable, ela pode ser tratada como tal.

A interface Runnable

Para utilizar multithreads em Java é necessário instanciar um objeto de uma classe que estende a classe básicaThread, certo?

Uma vez que Java não possui herança múltipla, como eu posso utilizar um objeto, cuja classe já é derivada, como no caso da ClasseThread? public class Filho extends Pai extends Thread {

……………….

} // isto nao eh possivel em Java

A interface Runnable

Cria-se uma thread (Classe Thread), passando para o seu construtor uma referência do objeto que implementa a interface Runnable.

Thread uma_Thread = new Thread(Runnable obj_thread)

Thread uma_Thread = new Thread(Runnable obj_thread, String nome_da_thread)

Exercício 5

Crie um programa onde o usuário possa escolher a quantidade de processos a serem criados para execução em concorrência.

Estes devem ser nomeados e atribuída prioridades valores de 1 até um valor máximo 10, passado para cada um deles.

Quando o processo atingir o número correspondente a metade do valor máximo do número de processos, deve entrar em espera de um tempo calculado de maneira randômica entre 1 e 5 segundos e posteriormente ser liberado. O programa deve ter um menu com as seguintes opções: 1) Criação de processos (qtd e nomes)2) Prioridades dos processos (int de 1 a 10)

Exercício 6 Veja a classe a seguir

É uma classe que implementa Runnable e, no método run(), apenas imprime dez mil números.

Vamos usá-las duas vezes para criar duas threads e imprimir os números duas vezes simultaneamente:

Exercício 6

Exercício 6 Se rodarmos esse programa, qual será a saída? De um a

mil e depois de um a mil? Provavelmente não, senão seria sequencial. 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, não sabemos exatamente qual é a saída.

Rode o programa várias vezes e observe: em cada execução a saída é um pouco diferente.

Depois mude a prioridade e veja como ocorre a execução.

Exercício 6 O problema é que no computador existe apenas um

processador capaz de executar coisas. E quando queremos executar várias 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 execução de cada uma delas.

A ideia é executar um pouco de cada thread e fazer essa troca tão rapidamente que a impressão que fica é que as coisas estão sendo feitas ao mesmo tempo.

Exercício 6 O escalonador é responsável por escolher qual a próxima thread

a ser executada e fazer a troca de contexto (context switch). Ele primeiro salva o estado da execução da thread atual para depois poder retomar a execução da mesma. Aí ele restaura o estado da thread que vai ser executada e faz o processador continuar a execução desta. Depois de um certo tempo, esta thread é tirada do processador, seu estado (o contexto) é salvo e outra thread é colocada em execução. A troca de contexto é justamente as operações de salvar o contexto da thread atual e restaurar o da thread que vai ser executada em seguida.

Quando fazer a troca de contexto, por quanto tempo a thread vai rodar e qual vai ser a próxima thread a ser executada, são escolhas do escalonador. Nós não controlamos essas escolhas (embora possamos dar "dicas" ao escalonador). Por isso que nunca sabemos ao certo a ordem em que programas paralelos são executados.

Exercício 6

Todo esse processo é feito automaticamente pelo escalonador do Java (e, mais amplamente, pelo escalonador do sistema operacional). Para nós, programadores das threads, é como se as coisas estivessem sendo executadas ao mesmo tempo.

Referências

Concurrent Programming - Hartley (capítulo 1)

Concurrent Programming in Java - Lea (capítulo 1, 2 e 3)

64

Programação Concorrente JAVA

Prof. Alexandre Monteiro

Recife

Recommended