A computação distribuída consiste em tempo e estado. Isto é, para que mais de um componente se comunique, é necessário compartilhar o estado, o que exige tempo.
A maioria dos programadores antropomorfiza seu trabalho. Eles enxergam um thread de controle executando todo o programa da mesma forma como enxergariam a si mesmos fazendo o trabalho inteiro por conta própria. Computadores modernos, entretanto, alternam entre tarefas com muita rapidez e, em sistemas multi-core, multi-CPU ou distribuídos, dois eventos podem ocorrer exatamente ao mesmo tempo. Defeitos rapidamente são postos nas lacunas entre o modelo do programador de como um programa é executado e o que ocorre na realidade. Esses defeitos estão relacionados com interações inesperadas entre threads, processos, tempo e informações. Essas interações ocorrem por meio de estados compartilhados: semáforos, variáveis, o sistema de arquivos e, basicamente, todas as coisas capazes de armazenar informações.
Code Correctness: Double-Checked Locking
Exemplo 1: À primeira vista, pode parecer que o seguinte trecho de código obtém a segurança de threads e, ao mesmo, evita a sincronização desnecessária.
if (fitz == null) {
synchronized (this) {
if (fitz == null) {
fitz = new Fitzer();
}
}
}
return fitz;
O programador quer garantir que apenas um objeto
Fitzer()
sempre seja alocado, mas não quer pagar o custo de sincronização cada vez que esse código é chamado. Essa expressão idiomática é conhecida como bloqueio duplamente verificado.Infelizmente, ele não funciona, e vários objetos
Fitzer()
podem ser alocados. Consulte a declaração "O bloqueio duplamente verificado está quebrado" para obter mais detalhes [1].