Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Lab-Threads

Laboratório de Desenvolvimento de Aplicações Web e Distribuídas

Aluna: Eduarda Vieira Gonçalves — Engenharia de Software


Conceitos iniciais

Processo

Um processo é um programa em execução. Ele possui seu próprio espaço de memória e recursos gerenciados pelo sistema operacional. Por exemplo, ao executar uma aplicação Java, o sistema operacional cria um processo para essa aplicação.

Thread

Uma thread é uma unidade de execução dentro de um processo. Um mesmo processo pode possuir várias threads executando tarefas de forma concorrente. As threads de um mesmo processo compartilham recursos, principalmente a memória.

Processo x Thread

Processo Thread
É uma aplicação em execução. É uma unidade de execução dentro do processo.
Possui seu próprio espaço de memória. Compartilha a memória do processo.
Possui maior custo de criação e gerenciamento. É mais leve e possui menor custo.
Processos diferentes são isolados entre si. Threads do mesmo processo compartilham recursos.
A comunicação entre processos é mais complexa. A comunicação entre threads é mais simples, mas exige cuidado com dados compartilhados.
Um processo pode conter várias threads. Uma thread pertence a um processo.

Uma forma simples de visualizar essa relação é pensar em uma empresa: o processo representa a empresa como um todo, enquanto as threads representam os funcionários executando diferentes tarefas dentro dela. Todos pertencem à mesma empresa e compartilham sua estrutura, mas cada um pode executar uma atividade diferente.


Exercícios

1. Trocar o pool fixo por newCachedThreadPool(). O comportamento muda?

Sim. O comportamento muda principalmente em relação à quantidade de threads utilizadas.

O newFixedThreadPool(4) trabalha com no máximo quatro threads e reutiliza essas threads durante a execução. Se houver mais tarefas do que threads disponíveis, as tarefas aguardam até que uma thread fique livre.

Já o newCachedThreadPool() cria novas threads conforme a necessidade e reutiliza threads que estão ociosas.

Portanto, o FixedThreadPool possui uma quantidade limitada de threads, enquanto o CachedThreadPool pode aumentar essa quantidade de acordo com a demanda, podendo consumir mais recursos.


2. Imprimir Thread.currentThread() na Parte E — é uma Virtual Thread?

Sim. Ao executar:

System.out.println(Thread.currentThread());

na Parte E, a saída apresentou a identificação VirtualThread, confirmando que as tarefas estavam sendo executadas utilizando Virtual Threads.

Exemplo observado:

VirtualThread[#100032]/runnable@ForkJoinPool-1-worker-10
VirtualThread[#100035]/runnable@ForkJoinPool-1-worker-4

Isso mostra que as threads utilizadas são gerenciadas pela JVM.


3. Processo x Thread — analogia do guichê de atendimento

Pense que o banco, como organização completa (prédio, sistema interno, caixa, cadastro de clientes e regras de funcionamento), é o processo. Já cada guichê com seu atendente é uma thread, ou seja, uma unidade de execução que realiza um trabalho específico dentro desse mesmo processo.

Na prática, vários atendentes conseguem trabalhar ao mesmo tempo, cada um atendendo um cliente diferente. Isso ilustra bem a concorrência entre threads: elas executam tarefas simultaneamente, mas continuam pertencendo ao mesmo processo e compartilhando recursos.

Resumo da analogia:

  • Banco inteiroProcesso
  • Guichê/atendenteThread
  • Sistema e estrutura do bancoRecursos compartilhados (memória do processo)
  • Outro banco separadoOutro processo (isolado)

A diferença principal é de custo e isolamento: abrir outro banco seria como criar um novo processo (mais pesado e independente), enquanto abrir mais um guichê no mesmo banco seria como criar uma nova thread (mais leve, porém compartilhando o mesmo ambiente).


4. Abordagem ideal para um servidor com milhares de conexões

Para um servidor que precisa lidar com milhares de conexões simultâneas, a melhor abordagem é utilizar Virtual Threads.

Elas são mais leves que as threads tradicionais do sistema operacional e permitem executar uma grande quantidade de tarefas simultaneamente com menor consumo de memória.

Em versões anteriores ao Java 21, uma alternativa seria utilizar ExecutorService com um pool de threads, limitando a quantidade de threads utilizadas.


Parte A

O tempo total ficou perto de 1s ou de 5s com 5 atendimentos? Por quê?

O tempo total ficou próximo de 1 segundo.

Isso acontece porque as cinco threads são executadas de forma concorrente. Todas entram em sleep() praticamente ao mesmo tempo e permanecem esperando por aproximadamente um segundo.

O join() apenas faz com que a thread principal aguarde a finalização das outras threads.

Portanto, as tarefas não são executadas uma após a outra:

Thread 1 ────── 1s
Thread 2 ────── 1s
Thread 3 ────── 1s
Thread 4 ────── 1s
Thread 5 ────── 1s

Tempo total ≈ 1s

Parte B

Qual das duas classes (Parte A ou B) poderia fazer herança de outra classe?

A classe da Parte B, que implementa Runnable.

Em Java, uma classe pode herdar de apenas uma classe. Na Parte A, a classe herda de Thread, portanto já utiliza sua possibilidade de herança.

Na Parte B, Runnable é uma interface. Assim, a classe pode implementar Runnable e ainda herdar de outra classe.

Essa abordagem também separa melhor a tarefa que será executada do objeto responsável por executar a thread.


Parte C

Por que criar uma thread de SO é mais caro do que criar um objeto comum em Java?

Uma thread tradicional possui recursos próprios, como memória de pilha e estruturas utilizadas pelo sistema operacional para seu gerenciamento e escalonamento.

Por isso, sua criação e manutenção possuem um custo maior do que a criação de um objeto comum em Java.

O que esse limite sugere sobre usar 1 thread por requisição em um servidor web?

Isso mostra que criar uma thread tradicional para cada requisição pode gerar um consumo muito alto de memória e processamento quando o servidor recebe muitas requisições simultaneamente.

Por isso, servidores podem utilizar Thread Pools para controlar a quantidade de threads ou Virtual Threads, que são mais leves.


Parte D

Com 4 threads atendendo 10 clientes, o tempo total ficou perto de 1s, 2s ou 3s?

O tempo total ficou próximo de 3 segundos.

Como existem apenas quatro threads disponíveis, os 10 clientes são processados em três grupos:

1º grupo → 4 clientes → ~1s
2º grupo → 4 clientes → ~1s
3º grupo → 2 clientes → ~1s

Assim:

1s + 1s + 1s ≈ 3s

As threads são reutilizadas para atender os próximos clientes assim que terminam suas tarefas.


Parte E

Uma Virtual Thread é uma thread de Sistema Operacional? Se não, o que ela é?

Não. Uma Virtual Thread não é uma thread tradicional do sistema operacional.

Ela é uma thread leve gerenciada pela JVM. A JVM utiliza threads reais do sistema operacional, chamadas de Carrier Threads, para executar as Virtual Threads.

De forma simplificada:

JVM
│
├── Carrier Thread
│   ├── Virtual Thread
│   ├── Virtual Thread
│   └── Virtual Thread
│
└── Carrier Thread
    ├── Virtual Thread
    ├── Virtual Thread
    └── Virtual Thread

Dessa forma, várias Virtual Threads podem ser executadas utilizando uma quantidade menor de threads do sistema operacional.

Isso permite que aplicações Java trabalhem com milhares de tarefas concorrentes de forma mais eficiente, principalmente em situações que envolvem espera por operações de I/O, como requisições HTTP e acesso a bancos de dados.


Conclusão

O laboratório permitiu observar na prática como funciona a concorrência em Java e como diferentes estratégias de criação e gerenciamento de threads afetam a execução das tarefas.

Os testes mostraram a diferença entre utilizar um número fixo de threads e permitir que novas threads sejam criadas conforme a demanda. Também foi possível observar o funcionamento das Virtual Threads e entender por que elas são uma alternativa interessante para aplicações que precisam lidar com muitas tarefas simultâneas.

Além disso, a comparação entre processos e threads mostrou que processos são unidades independentes de execução, enquanto threads são unidades de execução pertencentes a um processo e que compartilham seus recursos.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages