Muitos amigos podem ter ouvido falar da palavra -chave volátil e podem ter usado. Antes do Java 5, era uma palavra -chave controversa, pois usá -la em programas geralmente resultou em resultados inesperados. Somente depois que o Java 5 a palavra -chave volátil recuperou sua vitalidade. Embora a palavra -chave volátil seja literalmente simples de entender, não é fácil usá -la bem.
1. Prefácio
O JMM fornece definição variável volátil, blocos finais e sincronizados para garantir a visibilidade.
Para variáveis modificadas com volátil, o encadeamento lerá o valor mais modificado da variável toda vez que usa a variável. O volátil é facilmente mal utilizado e usado para operações atômicas. Eu escrevi alguns exemplos de teste, você pode tentar.
2. Programa principal
classe pública main {public static void main (string [] args) lança interruptedException {list <rehing> threadList = new ArrayList <Thread> (); para (int i = 0; i <10; ++ i) {thread thread = new Thread (new runnable () {@overridepublic void run () {Single.holder.instance.add ();}}); threadList.add (thread); thread.start ();} para (thread: threadlist) thread.join (); system.out.println (single.holder.instance.x);}}3. Teste de modo singleton
1. Sem volátil, sem sincronizado
classe single {public int x = 0; public void add () {try {timeUnit.millisEconds.sleep (50);} catch (interruptedException e) {e.printStackTrace ();} ++ this.x;} public class Static Holder {public static single instância = novo ();};Resultados da saída: 8, 9 e 10 apareceram. Você pode correr mais e tentar mais e encontrará resultados diferentes.
2. Há volátil, mas não sincronizado
classe única {public volátil int x = 0; public void add () {try {timeUnit.millisEconds.sleep (50);} catch (interruptedException e) {e.printStackTrace ();} ++ this.x;} public stict holder {public static single Instância = single ();};Resultado da saída: o número máximo de ocorrências é 9 e 10.
3. Sem volátil, sincronizado
classe única {public int x = 0; public sincronizado void add () {try {timeUnit.millisEconds.sleep (50);} catch (interruptedException e) {e.printStacktrace ();} ++ this.x;} public stick holder {public static instance = single ();};Resultado da saída: não importa quantas vezes você execute, será 10.
4. Sobre a aplicação de volátil em DCL (trava de verificação dupla)
classe pública Lazysingleton {private int somefield; private estático lazysingleton instância; private lazysingleton () {this.omefield = new Random (). NextInt (200) +1; // (1)} public static lazysingleton getInstance () {if (instance == null) {// (2) sincronizado (lazysingleton.class) {// (3) if (instance == null) {// (4) instância = new lazysingleton (); // (5)}}} retorna instância; // (6)} public int getSomefield () {return this.omefield; // (7)}}Primeiro de tudo, deixe -me explicar por que este método de escrita não funciona em Java!
Suponha que o Thread I esteja chamando o método getInstance () pela primeira vez, e depois o Thread II também chama o método getInstance () e getSomefield (). O que queremos explicar é que a declaração do thread I (1) não está acontecendo, antes da declaração do thread II (7). Quando o thread II executa a instrução (2) do método getInstance (), como o acesso à instância não está no bloco síncrono, o Thread II pode ou não observar a escrita do thread I na instância na instrução (5), ou seja, o valor da instância pode estar vazio ou não vazio. Primeiro, assumimos que o valor da instância não está vazio, por isso observamos o thread que eu escreva a instância. No momento, o Thread II executará a instrução (6) e retornará diretamente o valor desta instância e, em seguida, chamará o método getSomefield () nesta instância. Este método também é chamado sem qualquer sincronização. Portanto, toda a operação do Thread II é chamada sem sincronização. Isso mostra que não existe uma relação acontecer entre a declaração (1) do thread I e a declaração (7) do Thread II. Isso significa que o thread II pode não ser capaz de observar o valor escrito pelo thread I para algum ano no Declaração (1). Este é o problema com o DCL. É ridículo, certo? O DCL foi originalmente destinado a escapar da sincronização e alcançou esse objetivo. É precisamente por causa disso que acabou sendo punido. Existem bugs graves nesses programas, embora a probabilidade de esse erro ser descoberto seja definitivamente muito menor do que a probabilidade de ganhar na loteria e é fugaz. O mais aterrorizante é que, mesmo que isso aconteça, você não pensa que foi causado pelo DCL.
Meu entendimento é que thread I e Thread II têm seu próprio armazenamento de trabalho. Depois que o thread I cria a instância, o tempo para atualizar à memória é incerto; portanto, é inteiramente possível que o Thread II não possa observar o valor escrito pelo thread I para algum ano na declaração (1).
Portanto, porque há uma regra adicional antes adicionada no Java 5:
• Escreva a operação no campo volátil que aconteça antes das operações de leitura subsequente no mesmo campo.
Usando esta regra, podemos declarar a instância como volátil, ou seja: Instância de Lazysingleton estática volátil privada;
According to this rule, we can obtain the statement of thread I (5) -> sentence of thread II (2) (that is, thread), according to the single-thread rule, the statement of thread I (1) -> sentence of thread I (5) and sentence of thread II (2) -> sentence of thread II (7), and according to the delivery rules, there are the statement of thread I (1) -> sentence of thread II (7), which means that thread II can observe the Escreva o valor do thread I para algum pouco em declaração (1), e o programa pode obter o comportamento correto.
Suplemento: Antes do Java5, não há diferença entre a semântica síncrona do campo final e outras variáveis. No Java5, uma vez que a variável final é definida no construtor (desde que essa referência não seja vazada no construtor), outros threads definitivamente verão os valores definidos no construtor. O problema com o DCL é apenas que vemos o valor padrão da variável de membro do objeto, para que possamos definir a variável de campo de Lazysingleton para a final, para que ele possa ser executado corretamente no Java5.
O conteúdo acima é o conhecimento de palavras -chave voláteis em Java apresentado a você pelo editor. Espero que seja útil para todos!