Todo mundo adverte que o Java DateFormat não é seguro para threads e eu entendo o conceito teoricamente.
Mas não consigo visualizar quais problemas reais podemos enfrentar devido a isso. Digamos, eu tenho um campo DateFormat em uma classe e o mesmo é usado em métodos diferentes na classe (datas de formatação) em um ambiente com vários threads.
Isso causará:
- qualquer exceção, como exceção de formato
- discrepância nos dados
- alguma outra questão?
Além disso, explique o porquê.
java
multithreading
date-format
haps10
fonte
fonte
Respostas:
Vamos tentar.
Aqui está um programa no qual vários threads usam um compartilhado
SimpleDateFormat
.Programa :
Execute isso algumas vezes e você verá:
Exceções :
Aqui estão alguns exemplos:
1
2)
3)
Resultados incorretos :
Resultados corretos :
Outra abordagem para usar com segurança o DateFormats em um ambiente com vários threads é usar uma
ThreadLocal
variável para manter oDateFormat
objeto, o que significa que cada thread terá sua própria cópia e não precisará esperar que outros threads o liberem. É assim:Aqui está um bom post com mais detalhes.
fonte
Eu esperaria corrupção de dados - por exemplo, se você estiver analisando duas datas ao mesmo tempo, poderá ter uma chamada poluída por dados de outra.
É fácil imaginar como isso poderia acontecer: a análise geralmente envolve a manutenção de uma certa quantidade de estado sobre o que você leu até agora. Se dois threads estiverem pisando no mesmo estado, você terá problemas. Por exemplo,
DateFormat
expõe umcalendar
campo do tipoCalendar
e, observando o código deSimpleDateFormat
, alguns métodos chamamcalendar.set(...)
e outros chamamcalendar.get(...)
. Claramente, isso não é seguro para threads.Não examinei os detalhes exatos de por que
DateFormat
não é seguro para threads, mas para mim basta saber que é inseguro sem sincronização - as maneiras exatas de não segurança podem até mudar entre os lançamentos.Pessoalmente, eu usaria os analisadores do Joda Time , pois eles são seguros para threads - e o Joda Time é uma API de data e hora muito melhor para começar :)
fonte
Se você estiver usando o Java 8, poderá usar
DateTimeFormatter
.Código:
Resultado:
fonte
Grosso modo, você não deve definir uma
DateFormat
variável de instância como de um objeto acessado por vários threads oustatic
.Portanto, caso o seu
Foo.handleBar(..)
seja acessado por vários threads, em vez de:você deveria usar:
Além disso, em todos os casos, não possui um
static
DateFormat
Conforme observado por Jon Skeet, você pode ter variáveis estáticas e uma instância compartilhada, caso execute sincronização externa (por exemplo, use as
synchronized
chamadas para oDateFormat
)fonte
SimpleDateFormat
muita frequência. Depende do padrão de uso.Isso significa que, suponha que você tenha um objeto DateFormat e esteja acessando o mesmo objeto a partir de dois threads diferentes e esteja chamando o método format sobre esse objeto, o thread entrará no mesmo método ao mesmo tempo no mesmo objeto para que você possa visualizá-lo resultar em resultado adequado
Se você tiver que trabalhar com o DateFormat, como deve fazer alguma coisa
fonte
Os dados estão corrompidos. Ontem eu notei isso no meu programa multithread, onde eu tinha um
DateFormat
objeto estático e chameiformat()
de valores lidos via JDBC. Eu tinha a instrução SQL select, onde li a mesma data com nomes diferentes (SELECT date_from, date_from AS date_from1 ...
). Tais declarações foram usadas em 5 threads por várias datas noWHERE
usadas clasue. As datas pareciam "normais", mas diferiam em valor - enquanto todas as datas eram do mesmo ano, apenas o mês e o dia eram alterados.Outras respostas mostram o caminho para evitar essa corrupção. Eu fiz meu
DateFormat
não estático, agora é um membro de uma classe que chama instruções SQL. Testei também a versão estática com a sincronização. Ambos funcionaram bem, sem diferença no desempenho.fonte
As especificações de Format, NumberFormat, DateFormat, MessageFormat etc. não foram projetadas para serem seguras ao thread. Além disso, o método de análise chama o
Calendar.clone()
método e afeta as pegadas do calendário. Muitos segmentos analisados simultaneamente alteram a clonagem da instância do Calendário.Para mais, estes são relatórios de erros como este e este , com resultados do problema de segurança de thread do DateFormat.
fonte
Na melhor resposta, o dogbane deu um exemplo do uso da
parse
função e do que isso leva. Abaixo está um código que permite verificar aformat
função.Observe que, se você alterar o número de executores (threads simultâneos), obterá resultados diferentes. Dos meus experimentos:
newFixedThreadPool
definido como 5 e o loop falhará sempre.Eu estou supondo que YMMV, dependendo do seu processador.
A
format
função falha ao formatar a hora de um thread diferente. Isso ocorre porque aformat
função internamente está usando ocalendar
objeto configurado no início daformat
função. E ocalendar
objeto é uma propriedade daSimpleDateFormat
classe. Suspiro...fonte
Se houver vários threads manipulando / acessando uma única instância DateFormat e a sincronização não for usada, é possível obter resultados embaralhados. Isso ocorre porque várias operações não atômicas podem estar mudando de estado ou vendo a memória inconsistentemente.
fonte
Este é o meu código simples que mostra que DateFormat não é seguro para threads.
Como todos os threads estão usando o mesmo objeto SimpleDateFormat, ele lança a seguinte exceção.
Mas se passarmos objetos diferentes para threads diferentes, o código será executado sem erros.
Estes são os resultados.
fonte
Isso causará
ArrayIndexOutOfBoundsException
Além do resultado incorreto, ocorrerá uma falha de tempos em tempos. Depende da velocidade da sua máquina; no meu laptop, acontece uma vez a cada 100.000 chamadas, em média:
a última linha deve acionar a exceção do executor adiada:
fonte