Java volatile keyword

xindoo 2021-01-22 12:23:02
java volatile keyword

Java Medium volatile Keywords are used to mark variables as “ Stored in memory ”. Exactly every time volatile Variable read and write are direct operation memory , instead of cpu cache. Actually, ever since java 5 after ,volatile Except for volatile Variables read and write directly out of memory , It's also given more meaning , The article will explain later .

Variable visibility

java volatile Keywords ensure the visibility of variables changing between threads . Sounds like a little bit of leisure , Let me elaborate on .

In multithreaded applications , When thread operation is not volatile variable , Because of performance considerations , Each thread copies a variable from memory to cpu cache in ( translator's note : Reading and writing a disk requires 100ns,level1 cache It only needs 1ns). If your computer has more than one cpu, Each thread runs on a different cpu On , This means that each thread copies the variable to a different cpu cache On , Here's the picture .

For non volatile Variable ,JVM There is no guarantee that every time you write, you read and write from memory , This can lead to a series of problems .

Imagine a scene like this , Multiple threads operate on a variable containing a counter , as follows .

public class SharedObject {
public int counter = 0;

If only threads 1 Will increase counter, But threads 1 And thread 2 I read it from time to time counter.

If counter Not declared to be volatile,jvm It's not guaranteed every time counter Write cpu cache Will be synchronized to main memory . That means cpu cache The data in and main memory may not be consistent , As shown in the figure below .

Another thread can't read the latest variable value , Because the data hasn't come from cpu cache Synced to main memory , This is it. Visibility issues , Data updates are not visible to other threads .

Java volatile Visibility assurance

Java volatile Was born to solve the problem of visibility . hold counter Variable declared as volatile, all counter All writes are immediately written to main memory , All reads are read directly from main memory .

volatile Can be used as follows :

public class SharedObject {
public volatile int counter = 0;

Declare the variable as volatile Ensure the visibility of other threads to update this variable . In the example above , Threads 1 modify counter Variable , Threads 2 Read only without modification , hold counter Declare as volatile You can guarantee that the thread 2 Read the data correctly . at that time , If the thread 1 Threads 2 Will change this variable , that volatile There is no guarantee of the accuracy of the data , I'll explain it later .

volatile Full visibility guarantees

actually ,Java volatile Visibility guarantees go beyond volatile Variable itself . Visibility is guaranteed as follows . - If the thread A To modify a volatile Variable , And threads B Then I read the same variable , You thread A Writing volatile All variable operations before variables are in thread B Read volatile After changes to threads B It's all visible . - If the thread A Read out volatile Variable , So after it, the thread A All variables will be read again from main memory . The test code is as follows :

public class MyClass {
private int years;
private int months
private volatile int days;
public void update(int years, int months, int days){
this.years = years;
this.months = months;
this.days = days;

update() Method writes three variables , But only days Be declared volatile. volatile The meaning of full visibility assurance is : When the thread changes days, All variables are synchronized to main memory , ad locum years and months It will also be synchronized to main memory .

In the reading years、months、days When , You can do this .

public class MyClass {
private int years;
private int months
private volatile int days;
public int totalDays() {
int total = this.days;
total += months * 30;
total += years * 365;
return total;
public void update(int years, int months, int days){
this.years = years;
this.months = months;
this.days = days;

When calling totalDays() After the method , When reading days Later on total After the variable ,months and years It's also synchronized from main memory . If in the order above , It's guaranteed that you'll read days,months and years The latest value of .

translator's note : In the above specific reading and writing order , Although only days yes volatile Variable , but days and months It has also been realized. volatile. I guess the reason and cpu Hardware related ,volatile The address to be read before the variable is read is at cpu cache The center is invalid , This ensures that the data must be updated from memory before each read . Similarly, the synchronization will be forced after writing cache Data into main memory , That's it volatile semantics . But actually cpu cache In management cache Data is not in a single address , But with a block In units of , So a block Only one of them volatile Variable , So reading and writing this variable will result in the whole block Synchronize with main memory . in summary , I don't think this part of the original author's blog is referential ,java There's no such commitment , And this kind of visibility estimates and specific cpu To achieve something about , It may not be transferable , It's not recommended to use it like this . So if there are multiple variables that need visibility assurance , We still have to add everything volatile identification .

Instruction reordering challenges

Jvm and cpu It is possible to reorder the largest instruction for performance , But they all guarantee semantic consistency . for example :

int a = 1;
int b = 2;

These instructions can be rearranged in the following order with semantic correctness .

int a = 1;
int b = 2;

But when a variable is volatile When , Instruction reordering faces a challenge . Let's take another look at the above mentioned MyClass() Example .

public class MyClass {
private int years;
private int months
private volatile int days;
public void update(int years, int months, int days){
this.years = years;
this.months = months;
this.days = days;

When update() Method write days After the variable ,years and months The latest variables are also written , But if jvm Rearranged the instructions as follows :

public void update(int years, int months, int days){
this.days = days;
this.months = months;
this.years = years;

although months and years It will eventually be written to main memory as well , But not in real time , Immediate visibility to other threads cannot be guaranteed . The actual semantics will also change due to instruction reordering . Java In fact, this problem has been solved , Let's go on and see .

Java volatile And order (Happens-Before) Guarantee

To solve the challenge of reordering ,java volatile Keyword visibility also guarantees " Orderliness (happens-before)", The meaning of order assurance is as follows . - Read and write other variables if they are in the original volatile Before variables are written , You can't rearrange to volatile After variables are written . One volatile Read before variable write / Writing guarantees that before writing . Please note that there are special circumstances , for example , Yes volatile Read of other variables after write operation / The write operation will be on volatile Reorder before write operation of . Not vice versa . Back to front is allowed , But it's not allowed from the front to the back . - If you read other variables / Write if you were right in the beginning volatile Variable reading / After writing , It cannot be reordered to volatile Before reading . Please note that , In the reading volatile The reading of other variables before the variable can be done at the time of reading volatile The variables are then reordered . Not vice versa . From front to back is allowed , But back to front is not allowed .

above happens-before It's guaranteed that volatile Keyword strong visibility .

volatile Is not enough

Even though volatile Ensure that data read and write are directly operated from main memory , But there are many more cases volatile Semantics is not enough . In the previous example , Threads 1 Write counter Variable , If you will counter Declare as volatile, Threads 2 Always see the latest values .

But in fact , If multiple threads can write shared volatile Variable and the new value written each time does not depend on the old value , The accuracy of variable values can still be guaranteed , In other words, before a thread writes, it does not need to read it once, and then calculate the next value on the read data .

Reading out - Calculation - In the write mode, the correctness of the values can no longer be guaranteed , Because in the process of calculation , Under this time difference, the data may have been updated by other threads , Multiple threads may compete to write data , There will be data coverage .

So in the example above , Multiple threads update together counter Under the circumstances ,volatile There's no guarantee counter The accuracy of the numerical value has been improved . This situation will be explained in detail below .

Imagine threads 1 Read about counter A variable is 0, And then it added 1, But it didn't go back to main memory , It's written in cpu cache in . At this point the thread 2 Also see counter yes 0, It also adds 1 And only write about your own cpu cache in , Like the picture below .

At this point the thread 1 And thread 2 The data is actually out of sync . We expect counter The actual value should be 2, But in main memory it's 0, In a certain cpu cache Medium is 1. Finally, a thread cpu cache The data in will be synchronized and stored in main memory , But the data is wrong .

When volatile That's enough ?

As mentioned above , If there are multiple threads reading and writing volatile Variable , Only volatile It's not enough , You need to use synchronized To make sure that read and write is an atomic operation . Read and write a volatile Variables don't block other threads , To avoid that , You have to use synchronized key word .

except synchronized outside , You can still use it java.util.concurrent The atomic data types provided in the package , such as AtomicLong perhaps AtomicReferences. If only one thread writes , Other threads are read-only , that volatile That's enough , But don't use volatile Data visibility can't be guaranteed .

Be careful :volatile Ensure that only 32 Bit and 64 Visibility of bit variables .

volatile Performance considerations

volatile It will cause the data read and write to operate on the main memory directly , Read write main memory or read write cpu cache It's much slower .volatile Instruction reordering is also prohibited , Instruction reordering is a common means of performance optimization , So you should only use it when you really need to enforce variable visibility volatile.

Original address

Participation of this paper Tencent cloud media sharing plan , You are welcome to join us , share .


  1. 【计算机网络 12(1),尚学堂马士兵Java视频教程
  2. 【程序猿历程,史上最全的Java面试题集锦在这里
  3. 【程序猿历程(1),Javaweb视频教程百度云
  4. Notes on MySQL 45 lectures (1-7)
  5. [computer network 12 (1), Shang Xuetang Ma soldier java video tutorial
  6. The most complete collection of Java interview questions in history is here
  7. [process of program ape (1), JavaWeb video tutorial, baidu cloud
  8. Notes on MySQL 45 lectures (1-7)
  9. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  10. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  11. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  12. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  13. 【递归,Java传智播客笔记
  14. [recursion, Java intelligence podcast notes
  15. [adhere to painting for 386 days] the beginning of spring of 24 solar terms
  16. K8S系列第八篇(Service、EndPoints以及高可用kubeadm部署)
  17. K8s Series Part 8 (service, endpoints and high availability kubeadm deployment)
  18. 【重识 HTML (3),350道Java面试真题分享
  19. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  20. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  21. [re recognize HTML (3) and share 350 real Java interview questions
  22. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  23. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  24. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  25. RPC 1: how to develop RPC framework from scratch
  26. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  27. RPC 1: how to develop RPC framework from scratch
  28. 一次性捋清楚吧,对乱糟糟的,Spring事务扩展机制
  29. 一文彻底弄懂如何选择抽象类还是接口,连续四年百度Java岗必问面试题
  30. Redis常用命令
  31. 一双拖鞋引发的血案,狂神说Java系列笔记
  32. 一、mysql基础安装
  33. 一位程序员的独白:尽管我一生坎坷,Java框架面试基础
  34. Clear it all at once. For the messy, spring transaction extension mechanism
  35. A thorough understanding of how to choose abstract classes or interfaces, baidu Java post must ask interview questions for four consecutive years
  36. Redis common commands
  37. A pair of slippers triggered the murder, crazy God said java series notes
  38. 1、 MySQL basic installation
  39. Monologue of a programmer: despite my ups and downs in my life, Java framework is the foundation of interview
  40. 【大厂面试】三面三问Spring循环依赖,请一定要把这篇看完(建议收藏)
  41. 一线互联网企业中,springboot入门项目
  42. 一篇文带你入门SSM框架Spring开发,帮你快速拿Offer
  43. 【面试资料】Java全集、微服务、大数据、数据结构与算法、机器学习知识最全总结,283页pdf
  44. 【leetcode刷题】24.数组中重复的数字——Java版
  45. 【leetcode刷题】23.对称二叉树——Java版
  46. 【leetcode刷题】22.二叉树的中序遍历——Java版
  47. 【leetcode刷题】21.三数之和——Java版
  48. 【leetcode刷题】20.最长回文子串——Java版
  49. 【leetcode刷题】19.回文链表——Java版
  50. 【leetcode刷题】18.反转链表——Java版
  51. 【leetcode刷题】17.相交链表——Java&python版
  52. 【leetcode刷题】16.环形链表——Java版
  53. 【leetcode刷题】15.汉明距离——Java版
  54. 【leetcode刷题】14.找到所有数组中消失的数字——Java版
  55. 【leetcode刷题】13.比特位计数——Java版
  56. oracle控制用户权限命令
  57. 三年Java开发,继阿里,鲁班二期Java架构师
  58. Oracle必须要启动的服务
  59. 万字长文!深入剖析HashMap,Java基础笔试题大全带答案
  60. 一问Kafka就心慌?我却凭着这份,图灵学院vip课程百度云