Esse artigo faz parte da revista Java Magazine edição 11. Clique aqui para ler todos os artigos desta edição

 

 

Atenção: por essa edição ser muito antiga não há arquivo PDF para download.Os artigos dessa edição estão disponíveis somente através do formato HTML. 

 

Concorrência e a JVM

Threads e programação concorrente em Java

Nos artigos "Performance em Java" (Edição 3) e "Garbage Collection" (Edição 5), analisamos como a JVM executa código (interpretador/compilador JIT) e como gerencia memória (com ênfase no Garbage Collector). O terceiro elemento fundamental da arquitetura da JVM é o suporte à Programação Concorrente, que veremos neste artigo.

Suporte nativo

Assim como o gerenciamento de memória, o suporte à programação concorrente não costuma fazer parte da maioria das linguagens tradicionais, tais como C/C++. Nestas, em geral o programador utiliza APIs do Sistema Operacional (SO) diretamente. Quando muito, pode haver bibliotecas que encapsulam as primitivas do SO, de forma a facilitar um pouco seu uso na linguagem – no Visual C++, por exemplo, classes da MFC como CMutex e CWinThread. Em Java essas funcionalidades são suportadas não só por APIs mas também pelo runtime (JRE) e pela linguagem, o que  torna a programação concorrente muito mais fácil – além de portável.

Embora Java não tenha sido a primeira plataforma de desenvolvimento com suporte à programação concorrente, foi a primeira a tornar-se popular. Antes de Java só havia linguagens de pesquisa (como PROMELA) ou de nicho (como Erlang). Foi Java que introduziu a programação concorrente na rotina de muitos desenvolvedores anteriormente afastados pela complexidade e baixa portabilidade das alternativas disponíveis até então. Além disso, linguagens com suporte a concorrência anteriores a Java não eram modeladas em torno de threads, mas de outras primitivas, como processos e mecanismos de IPC (comunicação entre processos) otimizados para a programação concorrente. Outro fator que contribuiu foi a evolução dos sistemas operacionais, pois, no período em que Java apareceu, o recurso de multithreading, que poucos anos antes era raro em SOs de uso geral, tornou-se quase universal, e atualmente só não é encontrado em plataformas mais limitadas.

Threads

Java suporta a programação concorrente através de dois elementos fundamentais: o thread (java.lang.Thread) e o monitor. Este último é embutido no próprio layout de objetos Java, com API exposta por java.lang.Objectwait(), notify(), notifyAll() –, além de métodos ou blocos synchronized, que são “açúcar sintático” para funções do mesmo monitor. Em termos gerais, threads são subdivisões de um processo do SO que compartilham o mesmo espaço de endereçamento e outros recursos (como descritores de arquivos[1]), mas possuem um estado de execução[2] particular, podendo rodar em paralelo se houver várias CPUs, ou dividir o tempo de uma CPU.

O compartilhamento de memória torna threads mais leves que processos, e a comunicação entre threads – geralmente feita via variáveis compartilhadas – é mais eficiente que qualquer outro mecanismo de IPC. Pelo mesmo motivo (a ausência de proteção de memória), a programação com threads costumava ser pouco robusta: um crash ou uma corrupção de memória gerada por um thread afetaria todos os demais threads do mesmo processo.

Esse é outro motivo pelo qual a programação com threads se tornou mais popular com Java. Graças ao modelo de memória seguro, em Java é impossível (salvo bugs da JVM!) um thread mal-comportado afetar os demais desta forma. Na pior das hipóteses, um thread com bugs graves poderá induzir outros threads a deadlocks[3] e outros problemas algorítmicos. Mas até nesses casos, a JVM pode isolar grupos de threads que devem estar fortemente acoplados, de outros que não devem. Isso é um benefício adicional dos class loaders: em um container de Servlets, por exemplo, mesmo os piores bugs de uma aplicação web não conseguirão causar problemas em outra aplicação no mesmo processo, pois o container carrega os Servlets de cada contexto usando um class loader distinto, impedindo acesso indevido aos objetos de outras web-apps (o mesmo vale para aplicações corporativas hospedadas em servidores J2EE).

A implementação de threads e monitores pela JVM traz independência do sistema operacional, e aqui, como em outros casos, existem vantagens e desvantagens:

·         ...

Quer ler esse conteúdo completo? Tenha acesso completo