JMM(java内存模型)关键技术点都是围绕着多线程的原子性、可见性、有序性
来建立的。
原子性
原子性是指操作是不可分的,要么全部一起执行,要么不执行
。在java中,其表现在对于共享变量的某些操作,是不可分的,必须连续的完成。比如a++,对于共享变量a的操作,实际上会执行3个步骤:
- 读取变量a的值,假如a=1
- a的值+1,为2
- 将2值赋值给变量a,此时a的值应该为2
这三个操作中任意一个操作,a的值如果被其他线程篡改了,那么都会出现我们不希望出现的结果。所以必须保证这3个操作是原子性的,在操作a++的过程中,其他线程不会改变a的值,如果在上面的过程中出现其他线程修改了a的值,在满足原子性的原则下,上面的操作应该失败
。
java中实现原子操作的方法大致有2种:锁机制、无锁CAS机制
.
可见性
可见性是值一个线程对共享变量的修改,对于另一个线程来说是否是可以看到的
看一下java线程内存模型:
我们定义的所有变量都储存在 主内存中
- 每个线程都有自己 独立的工作内存,里面保存该线程使用到的变量的副本(主内存中该变量的一份拷贝)
- 线程对共享变量所有的操作都必须在自己的工作内存中进行,不能直接从主内存中读写(不能越级)
- 不同线程之间也无法直接访问其他线程的工作内存中的变量,线程间变量值的传递需要通过主内存来进行。(同级不能相互访问)
线程需要修改一个共享变量X,需要先把X从主内存复制一份到线程的工作内存,在自己的工作内存中修改完毕之后,再从工作内存中回写到主内存
。如果线程对变量的操作没有刷写回主内存的话,仅仅改变了自己的工作内存的变量的副本,那么对于其他线程来说是不可见的。而如果另一个变量没有读取主内存中的新的值,而是使用旧的值的话,同样的也可以列为不可见.
共享变量可见性的实现原理
- 线程A在自己的工作内存中修改变量之后,需要将变量的值刷新到主内存中
- 线程B要把主内存中变量的值更新到工作内存中
关于线程可见性的控制,可以使用volatile、synchronized、锁来实现
有序性
有序性指的是程序按照代码的先后顺序执行.
为了性能优化,编译器和处理器会进行指令冲排序,有时候会改变程序语句的先后顺序