Análise de visibilidade da programação concorrente Java volátil

visibilidade

Para o que é visibilidade, a explicação mais oficial é: a modificação de uma variável compartilhada por um thread pode ser vista por outro thread imediatamente.

Para ser franco, dois threads compartilham uma variável.Não importa qual thread modifique essa variável, o outro thread pode ver a modificação dessa variável pelo thread anterior. A variável compartilhada aqui significa que vários threads podem acessar e modificar o valor dessa variável, então essa variável é uma variável compartilhada.

Por exemplo, o thread A e o thread B, ambos modificam diretamente a variável compartilhada na memória principal. Se o thread A modifica a variável compartilhada ou o thread B modifica a variável compartilhada, a variável lida por outro thread da memória principal O valor deve ser um valor modificado, que é a visibilidade do encadeamento.

imagem.png

problema de visibilidade

O problema de visibilidade pode ser entendido da seguinte forma: uma thread modifica uma variável compartilhada, mas outra thread não consegue vê-la imediatamente, devido à adição de um cache pela CPU.

Depois de entender o que é visibilidade, fica mais fácil entender a questão da visibilidade. Visto que visibilidade significa que depois que um thread modifica a variável compartilhada, outro thread pode ver imediatamente a modificação da variável compartilhada.Se não puder ser visto imediatamente, isso causará problemas de visibilidade.

Sem problemas de visibilidade com CPUs single-core

Para entender o problema de visibilidade, precisamos prestar atenção para que não  haja problema de visibilidade em uma CPU de núcleo único . Por que é isso?

Porque em uma CPU single-core, não importa quantos threads sejam criados, apenas um thread pode obter recursos da CPU para executar tarefas ao mesmo tempo , mesmo que a CPU single-core tenha adicionado um cache. Essas threads estão todas rodando na mesma CPU, operando o cache da mesma CPU, desde que uma das threads modifique o valor da variável compartilhada, as outras threads devem ser capazes de acessar o valor da variável modificada.

imagem.png

Problemas de visibilidade com CPUs multi-core

Uma CPU de núcleo único tem apenas um thread em execução por vez e cada thread opera no mesmo cache da CPU durante a execução, portanto, não há problema de visibilidade para uma CPU de núcleo único. Mas quando se trata de CPUs multi-core, haverá problemas de visibilidade.

这是因为在多核CPU上,每个CPU的内核都有自己的缓存。当多个不同的线程运行在不同的CPU内核上时,这些线程操作的是不同的CPU缓存。一个线程对其绑定的CPU的缓存的写操作,对于另外一个线程来说,不一定是可见的,这就造成了线程的可见性问题。

imagem.png

例如,上面的图中,由于CPU是多核的,线程A操作的是CPU-01上的缓存,线程B操作的是CPU-02上的缓存,此时,线程A对变量V的修改对线程B是不可见的,反之亦然。

Java中的可见性问题

使用Java语言编写并发程序时,如果线程使用变量时,会把主内存中的数据复制到线程的私有内存,也就是工作内存中,每个线程读写数据时,都是操作自己的工作内存中的数据。

imagem.png

volatile 保证可见性原理

首先我们来了解以下JMM中的数据原子操作:

  • read(读取):从主内存读取数据
  • load(载入):将主内存读取到的数据写入工作内存
  • use(使用):从工作内存读取数据来计算
  • assign(赋值):将计算好的值从新赋值到工作内存中
  • store(存储):将工作内存数据写入到主内存
  • write(写入):将store过去的变量值赋值给主内存中的变量
  • lock(锁定):将主内存变量加锁,标识为线程独占状态
  • unlock(解锁):将主内存变量解锁,解锁后其他线程可以锁定该变量

Java中的volatile关键字是通过调用C语言实现的,而在更底层的实现上,即汇编语言的层面上,用volatile关键字修饰后的变量在操作时,最终解析的汇编指令会在指令前加上lock前缀指令

来保证工作内存中读取到的数据是主内存中最新的数据。具体的实现原理是在硬件层面上通过:MESI缓存一致性协议:多个cpu从主内存读取数据到高速缓存中,如果其中一个cpu修改了数据 ,会通过总线立即回写到主内存中,其他cpu会通过总线嗅探机制感知到缓存中数据的变化并将工作内存中的数据失效,再去读取主内存中的数据。

O Manual do desenvolvedor de software de arquitetura IA32 explica a instrução de prefixo de bloqueio:
1. Ele gravará imediatamente os dados da linha de cache do processador atual na memória do sistema,
2. Essa operação de gravar de volta na memória fará com que o endereço da memória seja armazenado em cache em outras CPUs Invalidação de dados (protocolo MESI)

imagem.png

Agora que sabemos que o volátil pode garantir a visibilidade das variáveis, também devemos saber que o volátil não pode garantir a atomicidade:

  Volátil não pode garantir atomicidade: Por exemplo: dois threads leem o mesmo valor na memória principal ao mesmo tempo, carregam-no na memória de trabalho e as CPUs dos dois threads usam o valor de contagem ao mesmo tempo e executam cálculos e atribuem de volta para a memória de trabalho, mas um deles O thread armazena de volta para a memória principal
mais rapidamente através do barramento, então o mecanismo de detecção de barramento da CPU sob o protocolo de coerência de cache MESI (barramento) invalidará a cópia variável na memória de trabalho de outro thread, resultando na perda dos resultados da operação anterior (pode ser entendido com imagens).

Supongo que te gusta

Origin juejin.im/post/7166790172258861064
Recomendado
Clasificación