Qual é a palavra-chave volátil útil para


Respostas:


741

volatilepossui semântica para visibilidade da memória. Basicamente, o valor de um volatilecampo se torna visível a todos os leitores (outros threads em particular) após a conclusão de uma operação de gravação. Sem volatile, os leitores poderiam ver algum valor não atualizado.

Para responder sua pergunta: Sim, eu uso uma volatilevariável para controlar se algum código continua um loop. O loop testa o volatilevalor e continua, se for true. A condição pode ser configurada falsechamando um método "stop". O loop vê falsee termina quando testa o valor após o método stop concluir a execução.

O livro " Concorrência Java na Prática ", que eu recomendo, fornece uma boa explicação volatile. Este livro foi escrito pela mesma pessoa que escreveu o artigo da IBM mencionado na pergunta (na verdade, ele cita seu livro na parte inferior desse artigo). Meu uso volatileé o que o artigo chama de "sinalizador de status padrão 1".

Se você quiser aprender mais sobre como volatilefunciona sob o capô, leia o modelo de memória Java . Se você quiser ir além desse nível, consulte um bom livro de arquitetura de computadores como Hennessy & Patterson e leia sobre a coerência e a consistência do cache.


118
Esta resposta está correta, mas incompleta. Ele omite uma propriedade importante volatileque veio com o novo Java Memory Model definido no JSR 133: quando um thread lê uma volatilevariá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 da volatilegravação. Veja esta resposta e esta referência .
Adam Zalcman

46
Para iniciantes, eu pediria que você demonstrasse com algum código (por favor?) #
Hungry Blue Dev

6
O artigo vinculado na pergunta tem exemplos de código.
Greg Mattes 22/02

Eu acho que o link 'Hennessy & Patterson' está quebrado. E o link para 'o modelo de memória Java' realmente leva ao Java Language Specification da Oracle 'Capítulo 17. Threads and Locks'.
Kris18

2
@efefi: "imediatamente" é um termo coloquial. Obviamente, isso não pode ser garantido quando nem o tempo de execução nem os algoritmos de agendamento de encadeamento são realmente especificados. A única maneira de um programa descobrir se uma leitura volátil é posterior a uma gravação volátil específica é verificar se o valor visto é o valor esperado esperado.
Holger

177

"... o modificador volátil garante que qualquer thread que leia um campo veja o valor gravado mais recentemente." - Josh Bloch

Se você está pensando em usar volatile, leia o pacote java.util.concurrentque trata do comportamento atômico.

A publicação da Wikipedia sobre um padrão Singleton mostra uso volátil.


18
Por que existem palavras volatile- synchronizedchave e ambos ?
ptkato

5
O artigo da Wikipedia sobre um padrão Singleton mudou muito desde então e não apresenta mais esse volatileexemplo. Pode ser encontrado em uma versão arquivada .
BSKP

1
@ptkato Essas duas palavras-chave servem a propósitos completamente diferentes; portanto, a questão não faz muito sentido como comparação, embora ambas estejam relacionadas à simultaneidade. É como dizer "Por que existem palavras void- publicchave e ambos ".
Davids

134

Ponto importante sobre volatile:

  1. A sincronização em Java é possível usando palavras synchronized- chave volatilee bloqueios Java .
  2. Em Java, não podemos ter synchronizedvariáveis. Usar synchronizedpalavra-chave com uma variável é ilegal e resultará em erro de compilação. Em vez de usar a synchronizedvariável em Java, você pode usar a volatilevariável java , que instruirá os encadeamentos da JVM a ler o valor da volatilevariável da memória principal e não a armazenará em cache localmente.
  3. Se uma variável não for compartilhada entre vários encadeamentos, não será necessário usar a volatilepalavra - 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 _instancevariável volatile, o Thread que está criando a instância de Singletonnã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 _instancecomo 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 _instancenã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 volatilepalavra - 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

insira a descrição da imagem aqui

volatileuso em Java :

Os iteradores à prova de falhas geralmente são implementados usando um volatilecontador no objeto de lista.

  • Quando a lista é atualizada, o contador é incrementado.
  • Quando um Iteratoré criado, o valor atual do contador é incorporado no Iteratorobjeto.
  • Quando uma Iteratoroperação é executada, o método compara os dois valores do contador e lança a ConcurrentModificationExceptionse 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.


2
"Os iteradores com falha rápida são normalmente implementados usando um contador volátil" - não é mais o caso, muito caro: bugs.java.com/bugdatabase/view_bug.do?bug_id=6625725
Vsevolod Golovanov

a verificação dupla de _instance é segura? eu pensei que eles não são seguros, mesmo com volátil
Dexters

"que instrui os encadeamentos da JVM a ler o valor da variável volátil da memória principal e não a armazena em cache localmente." bom ponto
Humoyun Ahmad

Para segurança da rosca, pode-se usar private static final Singleton _instance;também.
31318 Chris311

52

volatile é muito útil para interromper threads.

Não que você deva escrever seus próprios encadeamentos, o Java 1.6 possui muitos conjuntos de encadeamentos agradáveis. Mas se você tiver certeza de que precisa de um thread, precisará saber como interrompê-lo.

O padrão que eu uso para threads é:

public class Foo extends Thread {

  private volatile boolean close = false;

  public void run() {
    while(!close) {
      // do work
    }
  }
  public void close() {
    close = true;
    // interrupt here if needed
  }
}

No segmento de código acima, a leitura do thread closeno loop while é diferente daquela que chama close(). Sem volátil, o encadeamento que executa o loop pode nunca ver a alteração fechar.

Observe como não há necessidade de sincronização


2
Eu me pergunto por que isso é necessário. Isso não é necessário apenas se outros threads tiverem que reagir à alteração de status desse thread de forma que a sincronização dos threads esteja em perigo?
Jori

27
@ Jori, você precisa de volátil, porque a leitura de threads fechada no loop while é diferente daquela que chama close (). Sem volátil, o encadeamento que executa o loop pode nunca ver a alteração fechar.
Político

você diria que há uma vantagem entre interromper um thread como esse ou usar os métodos Thread # interrupt () e Thread # isInterrupted ()?
Ricardo Belchior

2
@Pyrolistical - Você já observou o tópico nunca vendo a mudança na prática? Ou você pode estender o exemplo para acionar esse problema de maneira confiável? Estou curioso, porque sei que usei (e vi outros usando) código basicamente idêntico ao exemplo, mas sem a volatilepalavra - chave, e sempre parece funcionar bem.
Aroth

2
@aroth: com as JVMs de hoje, você pode observar que, na prática, mesmo com os exemplos mais simples, no entanto, não é possível reproduzir esse comportamento de maneira confiável . Em aplicativos mais complexos, às vezes você tem outras ações com garantias de visibilidade da memória dentro do seu código, o que faz com que isso funcione, o que é especialmente perigoso, pois você não sabe por que ele funciona e uma simples alteração aparentemente não relacionada ao seu código pode interromper seu funcionamento. aplicação ...
Holger

31

Um exemplo comum de uso volatileé usar uma volatile booleanvariável como um sinalizador para finalizar um encadeamento. Se você iniciou um encadeamento e deseja interrompê-lo com segurança de um encadeamento diferente, pode fazer com que o encadeamento verifique periodicamente um sinalizador. Para pará-lo, defina o sinalizador como true. Ao fazer o sinalizador volatile, você pode garantir que o encadeamento que o está verificando seja definido na próxima vez que o verificar sem precisar usar um synchronizedbloco.


27

Uma variável declarada com volatilepalavra - chave tem duas qualidades principais que a tornam especial.

  1. Se tivermos uma variável volátil, ela não poderá ser armazenada em cache na memória cache do computador (microprocessador) por qualquer thread. O acesso sempre acontecia na memória principal.

  2. Se houver uma operação de gravação em uma variável volátil e, de repente, uma operação de leitura for solicitada, é garantido que a operação de gravação será concluída antes da operação de leitura .

Duas qualidades acima deduzem que

  • Todos os threads que lêem uma variável volátil definitivamente lerão o valor mais recente. Porque nenhum valor em cache pode poluí-lo. E também a solicitação de leitura será concedida somente após a conclusão da operação de gravação atual.

E por outro lado,

  • Se investigarmos mais detalhadamente o número 2 que mencionei, podemos ver que a volatilepalavra-chave é a maneira ideal de manter uma variável compartilhada que possui 'n' número de threads de leitor e apenas um thread de escritor para acessá-lo. Depois de adicionar a volatilepalavra-chave, ela está pronta. Nenhuma outra sobrecarga sobre segurança de rosca.

Inversamente,

Não podemos usar a volatilepalavra-chave apenas para satisfazer uma variável compartilhada que tenha mais de um segmento de gravador acessando-a .


3
Isso explica a diferença entre volátil e sincronizado.
ajay

13

Ninguém mencionou o tratamento da operação de leitura e gravação para o tipo variável longa e dupla. Leituras e gravações são operações atômicas para variáveis ​​de referência e para a maioria das variáveis ​​primitivas, exceto para tipos de variáveis ​​longas e duplas, que devem usar a palavra-chave volátil para serem operações atômicas. @ligação


Para torná-lo ainda mais claro, NÃO É NECESSÁRIO definir um volátil booleano, porque a leitura e gravação de um booleano JÁ é atômica.
Kai Wang #

2
@KaiWang, você não precisa usar voláteis em booleanos para fins de atomicidade. Mas você certamente pode, por razões de visibilidade. É isso que você quis dizer?
SusanW

12

Sim, o volátil deve ser usado sempre que você desejar que uma variável mutável seja acessada por vários encadeamentos. Não é um caso de uso muito comum, porque normalmente é necessário executar mais de uma única operação atômica (por exemplo, verificar o estado da variável antes de modificá-lo); nesse caso, você usaria um bloco sincronizado.


10

Na minha opinião, dois cenários importantes, além de interromper o encadeamento no qual a palavra-chave volátil é usada, são:

  1. Mecanismo de bloqueio verificado duas vezes . Usado frequentemente no padrão de design Singleton. Neste, o objeto singleton precisa ser declarado volátil .
  2. Despertares espúrios . Às vezes, o encadeamento pode acordar da chamada em espera, mesmo que nenhuma chamada de notificação tenha sido emitida. Esse comportamento é chamado de ativação espúria. Isso pode ser combatido usando uma variável condicional (sinalizador booleano). Coloque a chamada wait () em um loop while, desde que o sinalizador seja verdadeiro. Portanto, se o encadeamento acordar da chamada em espera por qualquer outro motivo que não seja o Notify / NotifyAll, o sinalizador ainda será verdadeiro e, portanto, as chamadas aguardarão novamente. Antes de ligar para a notificação, defina esse sinalizador como true. Nesse caso, o sinalizador booleano é declarado como volátil .

A seção # 2 inteira parece muito confusa, está confundindo notificações perdidas, ativações espúrias e problemas de visibilidade da memória. Além disso, se todos os usos do sinalizador estiverem sincronizados, o volátil será redundante. Acho que entendi seu ponto de vista, mas despertar espúrio não é o termo correto. Por favor, esclareça.
Nathan Hughes

5

Você precisará usar a palavra-chave 'volátil' ou 'sincronizado' e quaisquer outras ferramentas e técnicas de controle de simultaneidade que possa ter à sua disposição se estiver desenvolvendo um aplicativo multithread. Exemplo desse aplicativo são aplicativos de desktop.

Se você estiver desenvolvendo um aplicativo que seria implantado no servidor de aplicativos (Tomcat, JBoss AS, Glassfish, etc), não precisará lidar com o controle de simultaneidade, como já foi abordado pelo servidor de aplicativos. De fato, se eu me lembrei corretamente, o padrão Java EE proíbe qualquer controle de simultaneidade em servlets e EJBs, pois faz parte da camada de 'infraestrutura' que você deveria estar livre de manipulá-lo. Você só controla a simultaneidade nesse aplicativo se estiver implementando objetos singleton. Isso já foi abordado se você tricotar seus componentes usando o frameworkd, como o Spring.

Portanto, na maioria dos casos de desenvolvimento Java em que o aplicativo é um aplicativo da Web e usando a estrutura de IoC como Spring ou EJB, você não precisaria usar 'volátil'.


5

volatilegarante apenas que todos os threads, até eles mesmos, estão aumentando. Por exemplo: um contador vê a mesma face da variável ao mesmo tempo. Não é usado em vez de coisas sincronizadas ou atômicas ou outras coisas, faz completamente as leituras sincronizadas. Por favor, não o compare com outras palavras-chave java. Como o exemplo mostra abaixo, as operações variáveis ​​voláteis também são atômicas e fracassam ou são bem-sucedidas ao mesmo tempo.

package io.netty.example.telnet;

import java.util.ArrayList;
import java.util.List;

public class Main {

    public static volatile  int a = 0;
    public static void main(String args[]) throws InterruptedException{

        List<Thread> list = new  ArrayList<Thread>();
        for(int i = 0 ; i<11 ;i++){
            list.add(new Pojo());
        }

        for (Thread thread : list) {
            thread.start();
        }

        Thread.sleep(20000);
        System.out.println(a);
    }
}
class Pojo extends Thread{
    int a = 10001;
    public void run() {
        while(a-->0){
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Main.a++;
            System.out.println("a = "+Main.a);
        }
    }
}

Mesmo se você colocar resultados voláteis ou não, sempre será diferente. Mas se você usar AtomicInteger, os resultados abaixo serão sempre os mesmos. O mesmo ocorre com os sincronizados.

    package io.netty.example.telnet;

    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.atomic.AtomicInteger;

    public class Main {

        public static volatile  AtomicInteger a = new AtomicInteger(0);
        public static void main(String args[]) throws InterruptedException{

            List<Thread> list = new  ArrayList<Thread>();
            for(int i = 0 ; i<11 ;i++){
                list.add(new Pojo());
            }

            for (Thread thread : list) {
                thread.start();
            }

            Thread.sleep(20000);
            System.out.println(a.get());

        }
    }
    class Pojo extends Thread{
        int a = 10001;
        public void run() {
            while(a-->0){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Main.a.incrementAndGet();
                System.out.println("a = "+Main.a);
            }
        }
    }

4

Sim, eu uso bastante - pode ser muito útil para código multiencadeado. O artigo que você apontou é bom. Embora haja duas coisas importantes a serem lembradas:

  1. Você só deve usar o volátil se entender completamente o que faz e como difere a sincronização. Em muitas situações, o volátil parece, na superfície, ser uma alternativa mais simples e com melhor desempenho ao sincronizado, quando muitas vezes uma melhor compreensão do volátil deixaria claro que o sincronizado é a única opção que funcionaria.
  2. volátil, na verdade, não funciona em muitas JVMs mais antigas, embora sincronizado. Lembro-me de ver um documento que referenciava os vários níveis de suporte em diferentes JVMs, mas infelizmente não consigo encontrá-lo agora. Definitivamente, examine-o se você estiver usando Java pré 1.5 ou se não tiver controle sobre as JVMs nas quais seu programa estará executando.

4

Cada encadeamento que acessa um campo volátil lê seu valor atual antes de continuar, em vez de (potencialmente) usar um valor em cache.

Somente variável de membro pode ser volátil ou transitória.


3

Absolutamente sim. (E não apenas em Java, mas também em C #.) Há momentos em que você precisa obter ou definir um valor que é garantido como uma operação atômica em sua plataforma, um int ou booleano, por exemplo, mas não exige a sobrecarga do bloqueio da linha. A palavra-chave volátil permite garantir que, ao ler o valor, você obtenha o valor atual e não um valor em cache que tenha sido tornado obsoleto por uma gravação em outro encadeamento.


3

Existem dois usos diferentes de palavras-chave voláteis.

  1. Impede que a JVM leia valores do registro (assuma como cache) e força seu valor a ser lido da memória.
  2. Reduz o risco de erros de consistência na memória.

Impede a JVM de ler valores no registro e força seu valor a ser lido da memória.

Um sinalizador de ocupado é usado para impedir que um encadeamento continue enquanto o dispositivo está ocupado e o sinalizador não está protegido por um bloqueio:

while (busy) {
    /* do something else */
}

O segmento de teste continuará quando outro segmento desativar o sinalizador de ocupado :

busy = 0;

No entanto, como ocupado é acessado com freqüência no encadeamento de teste, a JVM pode otimizar o teste colocando o valor de ocupado em um registro e, em seguida, teste o conteúdo do registro sem ler o valor de ocupado na memória antes de cada teste. O encadeamento de teste nunca veria mudança ocupada e o outro encadeamento alteraria apenas o valor de ocupado na memória, resultando em conflito. Declarar o sinalizador de ocupado como volátil força seu valor a ser lido antes de cada teste.

Reduz o risco de erros de consistência da memória.

O uso de variáveis ​​voláteis reduz o risco de erros de consistência da memória , porque qualquer gravação em uma variável volátil estabelece um relacionamento "acontece antes" com leituras subsequentes dessa mesma variável. Isso significa que as alterações em uma variável volátil são sempre visíveis para outros threads.

A técnica de ler, escrever sem erros de consistência de memória é chamada de ação atômica .

Uma ação atômica é aquela que efetivamente acontece ao mesmo tempo. Uma ação atômica não pode parar no meio: ou acontece completamente ou não acontece. Nenhum efeito colateral de uma ação atômica é visível até que a ação seja concluída.

Abaixo estão as ações que você pode especificar que são atômicas:

  • As leituras e gravações são atômicas para variáveis ​​de referência e para a maioria das variáveis ​​primitivas (todos os tipos, exceto longos e duplos).
  • As leituras e gravações são atômicas para todas as variáveis ​​declaradas voláteis (incluindo variáveis ​​longas e duplas).

Felicidades!


2

Volátil faz o seguinte.

1> A leitura e gravação de variáveis ​​voláteis por diferentes threads são sempre da memória, não do cache ou do registro da própria CPU do thread. Portanto, cada thread lida sempre com o valor mais recente. 2> Quando 2 threads diferentes trabalham com a mesma instância ou variáveis ​​estáticas no heap, um pode ver as ações de outros como fora de ordem. Veja o blog de jeremy manson sobre isso. Mas volátil ajuda aqui.

O código a seguir em execução mostra como vários threads podem ser executados em ordem predefinida e imprimir saídas sem usar a palavra-chave sincronizada.

thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3
thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3
thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3

Para conseguir isso, podemos usar o seguinte código de execução completo.

public class Solution {
    static volatile int counter = 0;
    static int print = 0;
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Thread[] ths = new Thread[4];
        for (int i = 0; i < ths.length; i++) {
            ths[i] = new Thread(new MyRunnable(i, ths.length));
            ths[i].start();
        }
    }
    static class MyRunnable implements Runnable {
        final int thID;
        final int total;
        public MyRunnable(int id, int total) {
            thID = id;
            this.total = total;
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            while (true) {
                if (thID == counter) {
                    System.out.println("thread " + thID + " prints " + print);
                    print++;
                    if (print == total)
                        print = 0;
                    counter++;
                    if (counter == total)
                        counter = 0;
                } else {
                    try {
                        Thread.sleep(30);
                    } catch (InterruptedException e) {
                        // log it
                    }
                }
            }
        }
    }
}

O link a seguir no github possui um leia-me, que fornece uma explicação adequada. https://github.com/sankar4git/volatile_thread_ordering


2

volatilediz para um programador que o valor sempre estará atualizado. O problema é que o valor pode ser salvo em diferentes tipos de memória de hardware. Por exemplo, podem ser registros da CPU, cache da CPU, RAM ... Os registros da CPU e o cache da CPU pertencem à CPU e não podem compartilhar dados diferentes da RAM que estão sendo resgatados no ambiente de multithreading

insira a descrição da imagem aqui

volatileA palavra-chave diz que uma variável será lida e gravada diretamente da / para a memória RAM . Tem alguma pegada de computação

Java 5estendido volatileapoiando happens-before[Sobre]

Uma gravação em um campo volátil acontece antes de cada leitura subsequente desse campo.

volatileA palavra-chave não cura uma race conditionsituação em que vários encadeamentos podem gravar alguns valores simultaneamente. A resposta é synchronizedpalavra - chave [Sobre]

Como resultado, segurança somente quando um thread grava e outros apenas leem o volatilevalor

volátil vs sincronizado


1

Na página de documentação da Oracle , surge a necessidade de variável volátil para corrigir problemas de consistência da memória:

O uso de variáveis ​​voláteis reduz o risco de erros de consistência da memória, porque qualquer gravação em uma variável volátil estabelece um relacionamento de antes do acontecimento com leituras subsequentes dessa mesma variável.

Isso significa que as alterações em uma volatilevariável são sempre visíveis para outros threads. Isso também significa que, quando um thread lê uma variável volátil, ele vê não apenas as alterações mais recentes no volatile, mas também os efeitos colaterais do código que levou à alteração.

Conforme explicado na Peter Parkerresposta, na ausência de volatilemodificador, a pilha de cada thread pode ter sua própria cópia da variável. Ao fazer a variável como volatile, os problemas de consistência da memória foram corrigidos.

Dê uma olhada na página do tutorial de jenkov para entender melhor.

Dê uma olhada na pergunta SE relacionada para obter mais detalhes sobre casos voláteis e de uso para usar voláteis:

Diferença entre volátil e sincronizado em Java

Um caso de uso prático:

Você tem muitos segmentos, que precisam imprimir o tempo atual em um formato específico, por exemplo: java.text.SimpleDateFormat("HH-mm-ss"). Você pode ter uma classe, que converte o tempo atual em SimpleDateFormate atualiza a variável a cada segundo. Todos os outros threads podem simplesmente usar essa variável volátil para imprimir o horário atual nos arquivos de log.


1

Variáveis ​​voláteis são sincronização leve. Quando a visibilidade dos dados mais recentes entre todos os encadeamentos é requisito e a atomicidade pode ser comprometida, nessas situações as Variáveis ​​Voláteis devem ser preferidas. A leitura de variáveis ​​voláteis sempre retorna as gravações mais recentes feitas por qualquer encadeamento, pois elas não são armazenadas em cache em registradores nem em caches onde outros processadores não podem ver. Volátil é sem bloqueio. Eu uso volátil, quando o cenário atende aos critérios mencionados acima.


-1

A chave volátil, quando usada com uma variável, garantirá que os threads que lêem essa variável tenham o mesmo valor. Agora, se você tiver vários threads lendo e gravando em uma variável, tornar a variável volátil não será suficiente e os dados serão corrompidos. As threads de imagem leram o mesmo valor, mas cada uma delas realizou algumas alterações (por exemplo, um contador incrementado). Ao gravar de volta na memória, a integridade dos dados é violada. É por isso que é necessário sincronizar a variável (diferentes maneiras são possíveis)

Se as alterações forem feitas por 1 thread e os outros precisarem apenas ler esse valor, o volátil será adequado.


-1

A variável volátil é basicamente usada para atualização instantânea (liberação) na linha principal de cache compartilhado, uma vez atualizada, para que as alterações sejam refletidas em todos os threads de trabalho imediatamente.


-2

Abaixo está um código muito simples para demonstrar o requisito da volatilevariável for usada para controlar a execução do Thread a partir de outro thread (este é um cenário em que volatileé necessário).

// Code to prove importance of 'volatile' when state of one thread is being mutated from another thread.
// Try running this class with and without 'volatile' for 'state' property of Task class.
public class VolatileTest {
    public static void main(String[] a) throws Exception {
        Task task = new Task();
        new Thread(task).start();

        Thread.sleep(500);
        long stoppedOn = System.nanoTime();

        task.stop(); // -----> do this to stop the thread

        System.out.println("Stopping on: " + stoppedOn);
    }
}

class Task implements Runnable {
    // Try running with and without 'volatile' here
    private volatile boolean state = true;
    private int i = 0;

    public void stop() {
        state = false;
    } 

    @Override
    public void run() {
        while(state) {
            i++;
        }
        System.out.println(i + "> Stopped on: " + System.nanoTime());
    }
}

Quando volatilenão é usado: você nunca verá a mensagem ' Parado em: xxx ', mesmo depois de ' Parando em: xxx ', e o programa continua em execução.

Stopping on: 1895303906650500

Quando volatileusado: você verá o ' Interrompido: xxx ' imediatamente.

Stopping on: 1895285647980000
324565439> Stopped on: 1895285648087300

Demonstração: https://repl.it/repls/SilverAgonizingObjectcode


Para voto negativo: Cuidado para explicar por que voto negativo? Se isso não for verdade, pelo menos vou aprender o que está errado. Eu adicionei este mesmo comentário duas vezes, mas não sei quem está excluindo uma e outra vez
manikanta

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.