Olá pessoal!
Estamos lançando o sétimo stream do curso
Java Developer . Em mais de um ano de existência desse curso, ele foi refinado, aperfeiçoado, foi adicionado um novo que foi além desse período. O mesmo fluxo difere do restante, porque introduzimos um novo sistema de etapas, dividindo o curso em três partes e aumentando ligeiramente sua duração total. Portanto, agora não será necessário ficar exausto por cinco meses consecutivos para obter um certificado, mas escolher calmamente períodos de dois meses e receber treinamento. Mas essa é a letra, vamos voltar à nossa tradição sobre os diferentes utilitários que antecederam o lançamento do curso.
Vamos lá
1. Visão geral
O contêiner do servlet Java (ou servidor da web) é multithread: várias solicitações para o mesmo servlet podem ser executadas simultaneamente. Portanto, ao escrever um servlet, você deve considerar a concorrência.
Como dissemos anteriormente, uma e apenas uma instância de servlet é criada e, para cada nova solicitação, o Servlet Container cria um novo encadeamento para executar os métodos doGet () ou doPost () do servlet.
Por padrão, os servlets não são seguros para threads; o programador deve cuidar disso sozinho. Neste capítulo, discutiremos a concorrência de servlets. Este é um conceito muito importante, portanto, foque.
2. Visão geral dos threads

Um encadeamento é um processo leve que possui sua própria pilha de chamadas e acessa os dados abertos de outros encadeamentos no mesmo processo (heap compartilhado). Cada encadeamento possui seu próprio cache.
Quando dizemos que um programa é multithread, queremos dizer que a mesma instância de um objeto gera vários threads e processa um único elemento de código. Isso significa que vários fluxos de controle consecutivos passam pelo mesmo bloco de memória. Assim, vários encadeamentos executam uma instância de um programa e, portanto, compartilham variáveis de instância e podem tentar ler e gravar essas variáveis compartilhadas.
Vejamos um exemplo simples de Java.
public class Counter { int counter=10; public void doSomething() { System.out.println(“Inital Counter = ” + counter); counter ++; System.out.println(“Post Increment Counter = ” + counter); } }
Agora criamos dois threads Thread1 e Thread2 para fazer
doSomething()
. Como resultado, é possível que:
- Thread1 lê um valor de contador de 10
- Exibe contador inicial = 10 e vai aumentar
- Antes de o Thread1 incrementar o contador, o Thread2 também incrementa o contador, alterando o contador para 11
- Como resultado, o Thread1 tem um valor de contador 10, que já está desatualizado
Esse cenário é possível em um ambiente com vários threads, como servlets, porque as variáveis da instância são compartilhadas por todos os threads em execução na mesma instância.
3. Escrevendo servlets seguros para threads
Espero que nesta seção você entenda os problemas que estou tentando enfatizar. Se você tiver alguma dúvida, leia o ponto 2 novamente.
Há alguns pontos que precisamos considerar ao escrever servlets.
Service()
, doGet()
, doPost()
ou, de maneira mais geral, os métodos doXXX()
não devem atualizar ou modificar variáveis de instância, pois as variáveis de instância são compartilhadas por todos os threads da mesma instância.- Se houver necessidade de modificar a variável de instância, faça-o em um bloco sincronizado.
- Ambas as regras acima se aplicam a variáveis estáticas também porque elas também são comuns.
- Variáveis locais são sempre thread-safe.
- Os objetos de solicitação e resposta são seguros para uso em threads, porque uma nova instância é criada para cada solicitação em seu servlet e, portanto, para cada thread em execução em seu servlet.
A seguir, são apresentadas duas abordagens para garantir a segurança do encadeamento:
a) Sincronize o bloco no qual você modifica a instância ou variáveis estáticas (consulte o trecho de código abaixo).
Recomendamos que você sincronize o bloco no qual seu código modifica as variáveis da instância em vez de sincronizar o método completo para melhorar o desempenho.
Observe que precisamos bloquear a instância do servlet, pois precisamos tornar o encadeamento da instância do servlet específico seguro.
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class ThreadSafeServlet extends HttpServlet { @override public void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException int counter; { synchronized (this) {
b) Modelo de encadeamento único - implemente a interface SingleThreadModel para tornar o encadeamento único, o que significa que apenas um encadeamento executará o método service () ou doXXX () por vez. Um servlet de encadeamento único fica mais lento sob carga, porque novos pedidos devem aguardar o processamento de uma instância livre
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class ThreadSafeServlet extends HttpServlet implements SingleThreadModel { int counter;
O uso do SingleThreadModel foi descontinuado, pois é recomendável usar blocos sincronizados.
4. Conclusão
Devemos ter muito cuidado ao escrever servlets, porque "por padrão, servlets não são seguros para threads"
- Se o seu servlet não tiver nenhuma variável estática ou membro, você não precisa se preocupar e seu servlet é seguro para threads
- Se o seu servlet apenas ler a variável de instância, ele será seguro para threads.
- Se você precisar alterar uma instância ou variáveis estáticas, atualize-o em um bloco sincronizado, mantendo a instância bloqueada
Se você seguir as regras acima e na próxima vez que alguém lhe perguntar: "O encadeamento do servlet é seguro?" - responda com confiança: "Por padrão, eles não são, mas" Meus servlets "são seguros para threads."
O FIM
Como sempre, estamos aguardando suas perguntas, sugestões etc. aqui ou você pode perguntar a Sergey Petrelevich na
lição aberta sobre multithreading.