搜索
写经验 领红包
 > 育儿

java多线程volatile(java多线程基础知识)

导语:java基础篇 - 多线程 - volatile关键字为什么不满足原子性

之前面试的时候,被面试官问道“volatile关键字为什么不满足原子性”,当时没回答出来。抽时间研究了一下,恍然大悟。好了,废话不多,直接切入正题。

在并发编程中,需要满足如下3点,才能保证线程安全:可见性、有序性、原子性。

可见性 --> 当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。

有序性 --> 程序执行的顺序按照代码的先后顺序执行。

原子性 --> 一段程序要么全部执行,要么一点也不执行。如果执行的话,在执行的过程中不能被其它任何因素打扰。

对于volatile关键字声明的变量a,当线程1修改完变量a的值的时候,变量a的值会立即被刷新到主内存中,线程2要用到a的值的时候,迫使线程2从主内存中取a的值,而不是从线程2的副本变量中取a的值,从而保证线程的可见性。volatile关键字声明的变量,编译器会保证其有序性,有序性也无需考虑。但是volatile关键字声明的变量,无法保证原子性。

线程执行速率不一样

如上图所示:假设a被频繁用到,在线程内存中存有副本,值都是1。线程1和线程2执行的速率不一样(见图中标黄),当线程1执行到“a=a+1”的时候,线程2才执行到“代码2”。线程1执行完“a=a+1”,把a的值刷新到主内存,同时使线程2中a的副本变量失效,此时主内存中a的值变为2。当线程2执行到“a=a+1”的时候,因副本变量a失效,则从主存中取a的值2,然后执行a=a+1 ,得到的值是3。此结果是没有问题的。

线程执行速率一样

如上图所示:假设a被频繁用到,在线程内存中存有副本,值都是1。线程1和线程2执行的速率一样,都执行到了“a=a+1”。

“a=a+1”的执行可以分为3步:

1、从线程内存副本中取出a的值。

2、执行加1的操作。

3、更新线程内存副本的值并刷新至主内存。

因为线程1和线程2都执行到了“a=a+1”,假设线程1先从线程内存副本中取出a的值1,接着线程1阻塞,线程2从线程内存副本中取出a的值也是1。接着线程1和线程2都会执行到加1操作,计算的结果都是2,最后也都会刷新到主内存中,不论线程1和线程2谁先刷新到主内存,总之主内存中a的值都是2,不会是3,结果不对。

产生结果出错的原因是“a=a+1”操作不是原子操作,虚拟机执行“a=a+1”的指令是多条指令,这些指令集不是原子性的。

解决方案:

1、把a=a+1放在synchronized代码块中,保证只有一个线程执行。

2、把a定义成原子类,比如:AtomicInteger。

本文内容由快快网络小熊创作整理编辑!