Spring Boot — Race Condition e Ambiente Multi-Thread

Nick Borges
CWI Software

--

Em um ambiente com várias threads pode ocorrer o que chamamos de race condition, derivado de duas ou mais threads que tentam atualizar ou recuperar dados compartilhados que são mutáveis ao mesmo tempo(ambiente multi-thread), por exemplo, quando ocorrem diversas requisições simultâneas para uma API para alterar um recurso ou recuperar dados e o resultado não é retornado como esperado. Isso acontece porque não é garantido que o processamento será realizado na chamada devido a concorrência entre as chamadas feitas ao mesmo tempo e por não haver um sincronismo entre elas. Isso pode ocorrer com Spring Boot, pois quando o escopo de um bean não é definido ele assume o escopo default de bean do Spring que é o escopo singleton, o problema deste escopo é em relação ao uso de variáveis globais dentro de uma classe.

Escopo Singleton e o uso de variável global

Escopo singleton, diz ao contêiner do Spring para criar e gerenciar apenas uma instância da classe declarada, por contêiner. Esta única instância é armazenada em um cache de tais beans singleton e todas as solicitações e referências subsequentes para aquele bean retornam a instância em cache, ou seja o valor não muda.

Quando precisamos compartilhar o estado entre diferentes threads, por exemplo através de uma requisição que devolve algum resultado, ao realizar diversas requisições e utilizar variável global para retorno dados esse retorno pode não ser como esperado na próxima requisição caso os dados mudem. Para solucionar este problema em relação o escopo padrão singleton do Spring devemos manter a atenção e evitar o uso de variáveis globais e utilizar variáveis locais.

Exemplo:

Exemplo como uso correto.

Desta forma, quando houverem requisições estamos garantido o retorno correto evitando o uso de variável global.

Exemplo das requisições

Exemplo 1: Usando a variável global, vamos notar que o resultado não vai ser como esperado.

Exemplo de uso de variável global

Podemos notar que o primeiro request foi /pessoa/1?nome=Fulano1 e o segundo request foi /pessoa/2?nome=Fulano2 apenas transferindo os dados recebidos para o objeto de retorno. Porém o resultado não foi como esperado, os dados retornaram misturados e há casos em que os valores são nulos, isto porquê a chamada ao método que transfere os dados não inicia a variável global novamente.

Exemplo 2: Usando o mesmo exemplo anterior, porém agora sem usar variável global.

Agora sim, o resultado retornou como esperado, isto porque garantimos o sincronismo dos dados em relação ao escopo padrão singleton do Spring removendo o uso de variável global.

Referência

--

--