Ponto importante sobre volatile
:
- A sincronização em Java é possível usando palavras
synchronized
- chave volatile
e bloqueios Java .
- Em Java, não podemos ter
synchronized
variáveis. Usar synchronized
palavra-chave com uma variável é ilegal e resultará em erro de compilação. Em vez de usar a synchronized
variável em Java, você pode usar a volatile
variável java , que instruirá os encadeamentos da JVM a ler o valor da volatile
variável da memória principal e não a armazenará em cache localmente.
- Se uma variável não for compartilhada entre vários encadeamentos, não será necessário usar a
volatile
palavra - chave.
fonte
Exemplo de uso de volatile
:
public class Singleton {
private static volatile Singleton _instance; // volatile variable
public static Singleton getInstance() {
if (_instance == null) {
synchronized (Singleton.class) {
if (_instance == null)
_instance = new Singleton();
}
}
return _instance;
}
}
Estamos criando uma instância preguiçosamente no momento em que a primeira solicitação chega.
Se não fizermos a _instance
variável volatile
, o Thread que está criando a instância de Singleton
não poderá se comunicar com o outro thread. Portanto, se o Thread A está criando uma instância Singleton e logo após a criação, a CPU corrompe etc., todos os outros threads não poderão ver o valor _instance
como não nulo e acreditam que ainda é atribuído como nulo.
Por que isso acontece? Como os threads do leitor não estão bloqueando e até que o thread do gravador saia de um bloco sincronizado, a memória não será sincronizada e o valor de _instance
não será atualizado na memória principal. Com a palavra-chave Volatile em Java, isso é tratado pelo próprio Java e essas atualizações serão visíveis por todos os threads do leitor.
Conclusão : a volatile
palavra - chave também é usada para comunicar o conteúdo da memória entre os threads.
Exemplo de uso sem volátil:
public class Singleton{
private static Singleton _instance; //without volatile variable
public static Singleton getInstance(){
if(_instance == null){
synchronized(Singleton.class){
if(_instance == null) _instance = new Singleton();
}
}
return _instance;
}
O código acima não é seguro para threads. Embora verifique novamente o valor da instância no bloco sincronizado (por motivos de desempenho), o compilador JIT pode reorganizar o bytecode de maneira que a referência à instância seja definida antes que o construtor conclua sua execução. Isso significa que o método getInstance () retorna um objeto que pode não ter sido inicializado completamente. Para tornar o código seguro para encadeamento, a palavra-chave volátil pode ser usada desde o Java 5 para a variável de instância. Variáveis marcadas como voláteis ficam visíveis apenas para outros threads quando o construtor do objeto concluir sua execução completamente.
Fonte
volatile
uso em Java :
Os iteradores à prova de falhas geralmente são implementados usando um volatile
contador no objeto de lista.
- Quando a lista é atualizada, o contador é incrementado.
- Quando um
Iterator
é criado, o valor atual do contador é incorporado no Iterator
objeto.
- Quando uma
Iterator
operação é executada, o método compara os dois valores do contador e lança a ConcurrentModificationException
se eles forem diferentes.
A implementação de iteradores à prova de falhas é geralmente leve. Eles geralmente contam com propriedades das estruturas de dados da implementação de lista específica. Não há padrão geral.
volatile
que veio com o novo Java Memory Model definido no JSR 133: quando um thread lê umavolatile
variável, vê não apenas o último valor gravado nele por algum outro thread, mas também todas as outras gravações em outras variáveis que eram visíveis nesse outro segmento no momento davolatile
gravação. Veja esta resposta e esta referência .