Competição Servlet

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:

  1. Thread1 lê um valor de contador de 10
  2. Exibe contador inicial = 10 e vai aumentar
  3. Antes de o Thread1 incrementar o contador, o Thread2 também incrementa o contador, alterando o contador para 11
  4. 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.

  1. 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.
  2. Se houver necessidade de modificar a variável de instância, faça-o em um bloco sincronizado.
  3. Ambas as regras acima se aplicam a variáveis ​​estáticas também porque elas também são comuns.
  4. Variáveis ​​locais são sempre thread-safe.
  5. 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) { //code in this block is thread-safe so update the instance variable } //other processing; } 

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; // no need to synchronize as implemented SingleThreadModel @override public void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } 

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"

  1. 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
  2. Se o seu servlet apenas ler a variável de instância, ele será seguro para threads.
  3. 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.

Source: https://habr.com/ru/post/pt414759/


All Articles