Buscar

Sistema Concorrente

Prévia do material em texto

Conceitos e Implementação de um Sistema Concorrente 
Orientado a Objeto 
Paulo Roberto Gonçalves, Thereza Patrícia P. Padilha 
Curso de Sistemas de Informação 
Centro Universitário Luterano de Palmas (CEULP) Palmas, TO, Brasil 
{prg,thereza}@ulbra-to.br 
 
Resumo. A maioria dos sistemas concorrentes implementados utiliza o 
paradigma orientado a objeto. Diante disso, este artigo apresenta alguns 
conceitos da programação de sistemas concorrentes orientados a objetos, bem 
como descreve a implementação de um ambiente de aprendizado colaborativo 
usando classes Threads em Java. 
1 Introdução 
Os recentes desenvolvimentos de redes locais de alto desempenho têm despertado grande 
interesse em sistemas distribuídos, que consistem de diversos computadores que podem 
operar independentemente, mas interconectados eficientemente. 
 A comunicação em sistemas distribuídos pode ser realizada através da chamada de 
procedimentos remota (Remote Procedure Call - RPC). A implementação de RPC envolve 
a transferência de solicitações do cliente para o servidor e dos resultados do servidor para o 
cliente. A limitação do RPC é a transferência de informações entre dois computadores apenas 
(cliente e servidor). 
 Diante dessa limitação, surgiu a comunicação em grupo que permite a um usuário 
enviar uma mensagem para um ou mais membros ao mesmo tempo. Quando um usuário envia 
uma mensagem para outro usuário a comunicação é chamada de ponto-a-ponto. Quando um 
usuário envia uma mensagem para vários usuários, a comunicação é chamada de um-para-
vários [Tanenbaum 1995]. 
 A maioria dos sistemas distribuídos possibilita a existência de múltiplas threads num 
único processo, sendo neste caso mais conhecido como multithread. Esta habilidade provê 
alguns benefícios importantes como: a rapidez de resposta para o usuário, o compartilhamento 
de memória e de outros recursos do processo a qual pertencem e economia com relação à 
alocação de memória e recursos para a criação de processos. Porém também introduz alguns 
problemas como: complexidade e a possibilidade de um menor desempenho da máquina, que 
ocorre quando uma thread que executa freqüentemente, mas realiza poucas tarefas a cada 
execução [Silberschatz et al. 2000]. 
 
 O objetivo deste trabalho é apresentar os conceitos envolvidos na programação de 
sistemas concorrentes orientados a objetos, bem como descrever a implementação de um 
ambiente de aprendizado colaborativo usando as classes Threads em Java. 
 Além do alto grau de recursos oferecidos, a linguagem de programação Java é 
multiplataforma, permitindo que um mesmo programa possa ser utilizado em máquinas com 
sistemas operacionais diferentes, garantindo a portabilidade de qualquer aplicação 
implementada nessa linguagem. Além disso, o Java disponibiliza primitivas de concorrência. 
Estas foram relevâncias que nos levaram a escolher a linguagem Java. 
 Este artigo está organizado da seguinte forma: na seção 2 é apresentada uma visão 
geral sobre programação concorrente; na seção 3 são abordados os principais conceitos 
associados com sistemas contendo threads e multithreads, bem como a sua utilização na 
linguagem Java; na seção 4 é apresentada, como um estudo de caso, a implementação de um 
ambiente colaborativo usando classes Threads em Java; e na seção 5 são descritas as 
considerações finais do trabalho. 
 
2 Programação Concorrente: visão geral 
Um programa seqüencial é composto por um conjunto de instruções que são executadas 
seqüencialmente, sendo que a execução dessas instruções é denominada processo. Um 
programa concorrente especifica dois ou mais programas seqüenciais que podem ser 
executados concorrentemente como processos paralelos [Santana et al. 1997]. 
 Historicamente, a concorrência foi introduzida nos sistemas de computação como um 
meio para aumentar a performance. Os primeiros computadores foram máquinas seriais que 
processavam os dados bit a bit, ou seja, um bit a cada ciclo. Para aumentar o desempenho, 
os computadores passaram a processar os dados em palavras de diversos bits a cada ciclo. 
 Um novo aumento do desempenho foi obtido ao arranjar as operações de CPU e de 
entrada e saída em paralelo. Isto imediatamente impulsionou a programação concorrente e o 
desenvolvimento de mecanismos e sistemas operacionais que suportassem a concorrência e o 
paralelismo de operações. 
 A programação concorrente pode ser executada em um só processador, explorando 
o que se chama de pseudoparalelismo, ou em vários processadores, passando a ser chamada 
de programação paralela, que se caracteriza pela execução de várias tarefas ao mesmo 
instante. A programação concorrente diferencia-se de programação paralela e distribuída, da 
seguinte forma: na programação paralela os processos são executados simultaneamente, em 
um computador com multiprocessadores, que se encarregam dos diversos processos em 
paralelo, na programação distribuída os processos são executados em vários computadores 
ligados através de uma rede [Santana et al. 1997]. 
 As linguagens específicas para a programação concorrente apresentam flexibilidade, 
clareza para ativação e coordenação de processos, ferramentas para depuração e detecção 
de erros, e alto desempenho. Exemplos dessas linguagens são: Ada e Java. 
 
 
3 Threads e Multithreads em Java 
Um programa em execução é chamado de processo. Cada processo possui, no mínimo, uma 
thread, que nada mais é que um fluxo de execução. Os processos também podem ser 
executados com múltiplas threads, realizando mais de uma tarefa de cada vez (multithread). 
A figura 1 apresenta a diferença entre um processo de uma única thread e um processo com 
múltiplas threads [Silberschatz et al. 2000]. 
 
 
Figura 1. Processos com um e múltiplas threads [Silberschatz et al 2000] 
 
 Um programa multithread é aquele que pode ser descrito como efetuando diversas 
atividades ao mesmo tempo. Um exemplo de programa multithread seria uma aplicação 
servidora, pois, tipicamente um servidor atende a vários pedidos de cliente. Utilizar um 
servidor com uma só thread significa que cada pedido terá que esperar o pedido anterior 
terminar, isso torna-se lento e ineficiente. Por outro lado, o uso de um servidor multithread 
atenderia a vários pedidos simultaneamente [Silberschatz et al. 2000]. 
 Em Java, mesmo um programa simples com apenas o método main() é executado 
como uma thread. Essa linguagem também oferece diversos comandos para a criação e a 
manipulação de classes do tipo Threads. A maneira mais simples de se declarar uma classe 
Thread é criar uma subclasse derivada da classe Thread. Nessa nova classe também é 
preciso gerar um método run(), que vai ser executado quando a thread for instanciada. A 
criação de uma classe thread e o seu método run() podem ser observados na figura 2, sendo 
que esta apresenta um programa que instancia duas threads que serão executadas 
concorrentemente, sem especificar a ordem de execução dessas threads. 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Figura 2: Criação de uma classe Thread em Java 
 
 Uma classe em Java pode herdar métodos e atributos de apenas uma outra classe 
(herança simples), sendo que não é permitida a herança múltipla. Essa limitação pode ser 
resolvida com a utilização da interface Runnable, que é semelhante a uma classe abstrata, ou 
seja, uma classe que não permite instanciar objetos. Nesse caso é preciso implementar e não 
herdar, sendo que uma classe pode implementar várias interfaces. Um exemplo de criação de 
threads por meio da interface Runnable pode ser observado na figura 3. 
 Enfim, as formas possíveis de se criar classes threads em Java são: a partir da classe 
Thread (extends Threads, figura 2) e implementando a interface Runnable (implements 
Runnable, figura 3). 
 class testeThread extends Thread {private String nome; 
 public testeThread (String str){ 
 nome = str; 
 } 
 public void run(){ 
 system.out.println(“Começar”); 
 system.out.println(“Em execução - ” + nome); 
 sleep(1); 
 system.out.println(nome + “ - Terminou”); 
 } 
 public static void main(String args[]) { 
 testeThread um = new testeThread(“Thread 1”); 
 testeThread dois = new testeThread(“Thread 2”); 
 um.start(); 
 dois.start(); 
 } 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Figura 3: Criação de thread por meio da interface Runnable 
 
 Uma thread pode estar em um dos quatro estados possíveis, que são: 
- novo: quando um objeto thread é criado; 
- executando: quando uma thread está em execução; 
- bloqueado: quando uma thread fica bloqueada esperando a resposta de algum 
método, como sleep() ou suspend(), ou quando executa uma operação de I/O a qual 
é bloqueante; 
- terminado: quando uma thread termina seu método run() ou quando o método stop() 
é chamado. 
 Na figura 4 são apresentados os estados possíveis de uma thread, bem como os 
métodos que provocam a transição de estados. Apresenta também o trajeto que uma 
determinada thread pode seguir, por exemplo, uma thread só pode ser bloqueada quando 
estiver executando. 
 class testeThread implements Runnable { 
 private String nome; 
 public testeThread (String str){ 
 nome = str; 
 } 
 public void run(){ 
 system.out.println(“Começar”); 
 system.out.println(“Em execução - ” + nome); 
 sleep(1); 
 system.out.println(nome + “ - Terminou”); 
 } 
 public static void main(String args[]) { 
 testeThread um = new testeThread(“Thread 1”); 
 testeThread dois = new testeThread(“Thread 2”); 
 new Thread(um).start(); 
 new Thread(dois).start(); 
 } 
 
 
Figura 4: Estados de uma thread Java [Silberschatz et al 2000] 
 
 A linguagem Java fornece vários métodos para o controle dos estados de uma 
thread, são eles: start(), suspend(), sleep(), resume() e stop(). O método start() inicia a 
execução de uma thread. O método suspend() suspende a execução de uma thread que 
estiver processando no momento. O método sleep() suspende a thread em execução durante 
um determinado período. O método resume() retorna a execução de uma thread que tinha 
sido suspensa. Por fim, o método stop() interrompe a execução de uma thread. Após ser 
interrompida, uma thread não poderá ser retomada ou iniciada. 
 Na linguagem Java, toda linha de execução tem uma certa prioridade, que varia entre 
1 e 10. Por definição, uma linha de execução herda a prioridade da sua linha de execução 
progenitora. É possível aumentar ou diminuir a prioridade de qualquer linha de execução por 
meio do método setPriority(). Quando, o scheduler (conjunto de políticas e de 
mecanismos incorporados no sistema operacional que determinam a ordem em que as 
threads executam) selecionar uma nova linha de execução, geralmente a que possui a maior 
prioridade é escolhida [Horstman & Cornell 2001]. Em geral, as prioridades das threads são 
alteradas apenas quando existe uma grande necessidade de um fluxo terminar uma execução 
antes dos demais. 
 Existe concorrência num programa Java quando há mais do que uma thread ativa. Na 
execução de múltiplos threads, quando uma thread está em execução, as outras estão 
bloqueadas ou aguardando a liberação do processador. 
 
4 Um Estudo de Caso 
O ambiente de aprendizado colaborativo via Internet, que está sendo desenvolvido, agrega 
várias ferramentas de comunicação, que são: editor de edição colaborativa, votação e chat. A 
implementação deste ambiente utiliza a linguagem Java pelo fato desta possuir uma alta 
portabilidade, bem como facilidade de suporte à distribuição e concorrência. Em termos de 
implementação, cada ferramenta foi considerada como uma aplicação separada, mas com o 
objetivo de propiciar a colaboração como um todo. 
 Cada ferramenta possui um servidor que aguarda as solicitações de clientes, sendo 
que cada conexão de cliente é transformada em uma thread, tornando-se assim uma 
aplicação multithread. Na figura 5 é apresentado um trecho de código da criação das 
threads clientes. 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Figura 5: Trecho de código de criação de threads clientes 
 
 Esse trecho mostra como foi criada a classe MultiServerThread, que herda os 
atributos e métodos da classe Thread e recebe um objeto do tipo socket para conexão. Vale 
ressaltar que todas as threads criadas possuem a prioridade padrão, isto é, o valor 5. É 
implementado também o método run(), o qual será executado quando o objeto dessa classe 
for instanciado. Esse método possui alguns procedimentos adotados para a implementação da 
conexão com o servidor e do envio de informações. 
 Como recurso de rede e de comunicação distribuída, foram utilizados sockets, que 
atuam como uma espécie de ponte que é estabelecida entre os dois processos. Uma vez 
criada essa ponte, os programas conseguem transmitir e receber informações. Esse modelo de 
comunicação segue a arquitetura cliente/servidor, na qual existe uma entidade (servidor) que 
disponibiliza um serviço e uma outra entidade que utiliza este serviço (cliente). 
 No servidor, existe um repositório contendo pastas e arquivos dos usuários do 
ambiente, nos quais são compartilhados pelas threads. Alguns fatores importantes do 
compartilhamento são a consistência e a segurança das informações, uma vez que várias 
threads podem estar trabalhando juntamente. 
public class MultiServerThread extends Thread { 
 private Socket connection; 
 ObjectInputStream input; 
 MultiServerThread(Socket conn) { 
 connection = conn; 
 } 
 public void run() { 
 try { 
 Vector vCliente; 
 Vector vServidor = new Vector(); 
 ObjectInputStream input; 
 Input = new ObjectInputStream (connection.getInputStream()); 
 vCliente = (Vector)input.readObject(); 
 vServidor.addElement(vCliente.elementAt(0)); 
 vServidor.addElement(vCliente.elementAt(1)); 
 vServidor.addElement( 
 new ObjectOutputStream (connection.getOutputStream())); 
 
 
5 Considerações Finais 
Este artigo apresentou alguns conceitos e a implementação de um sistema concorrente 
orientado a objeto. Pode-se observar que o uso de threads para a implementação torna a 
aplicação bem mais eficiente e mais rápida, pelo fato de existirem várias threads trabalhando 
em paralelo. 
 Pode-se concluir a eficiência da linguagem Java para aplicações voltadas à confecção 
de ambientes de aprendizado colaborativo, por fornecer recursos que permitam a 
implementação de técnicas de colaboração. Outro aspecto positivo de uma aplicação 
construída em Java é o fato da mesma ser orientada a objetos, que proporciona benefícios 
como: a extensibilidade, reusabilidade, manutenção, entre outros. 
 Além disso, pode-se verificar o poder da linguagem Java para os recursos de sockets 
(cliente/servidor), construção de múltiplas linhas de execução – concorrência (threads) e 
acesso à banco de dados, devido já existirem várias classes e construtores implementados, o 
que acelera e facilita a implementação. 
 Uma grande parte do uso da linguagem Java em aplicações concorrentes deve-se ao 
suporte para threads no nível da linguagem. Todos os programas Java consistem em pelo 
menos uma thread de controle, sendo fácil criar várias threads de controle no mesmo 
programa. Além de fornecer um conjunto de APIs para a criação e o gerenciamento de 
threads. 
 A implementação das ferramentas do ambiente colaborativo usando as classes 
Threads separadas tem sido satisfatória com o intuito de torná-la mais robusta. Um dos 
problemas encontrados foi a comunicaçãodos processos, mais precisamente envio e 
recebimento de informações do servidor para as threads clientes. Este trabalho também 
serviu para consolidar e aprimorar os conceitos de programação concorrente vistos. 
 
Referências Bibliográficas 
[Arnold & Gosling 1997] Arnold, K., Gosling, J. “Programando em Java”, Tradução: Adriana 
de Almeida Prado Krauss, São Paulo: Makron Books, 1997. 
[Deitel & Deitel 2001] DEITEL, H. M.; DEITEL, P. J. “Java como programar”, Tradução: 
Edson Furnankiewicz, Porto Alegre: Bookman , 2001. 
[Horstman & Cornell 2001] Horstman C. S.; Cornell, G. CoreJava 2 – Recursos Avançados. 
Tradução: João Eduardo N. Tortello Revisão Técnica: Álvaro R. Antunes. São Paulo: 
MAKRON Books, Vol. II, 2001. 
[Santana et al. 1997] Santana, R. H.; Santana, M. J.; Souza, M. A.; Souza, P. S. L.; 
Piekarski, A. E. T. Computação Paralela. Notas de Aula (no prelo), ICMC-USP, 1997. 
[Silberschatz et al. 2000] Silberschatz, A., Galin, P. and Gagne, G. “Sistemas Operacionais: 
conceitos e aplicações”, Tradução: Adriana Rieche, Rio de Janeiro: Campus, 2000. 
 
[Tanenbaum 1995] Tanenbaum, A. S. “Distributed operating Systems”, New Jersey: 
Prentice-Hall, 1995.

Outros materiais