假设对共享变量除了赋值之外并不完成其他操作,那么可以将这些共享变量声明为volatile。
如果把一个事务可看作是一个程序,它要么完整的被执行,要么完全不执行。这种特性就叫原子性。
由原子的不可分性可知,原子性是拒绝多线程操作的。(因为多线程的运行方式为抢占式,而原子又不可分,就像未来有三千万人娶不到媳妇,每一个人“抢到”媳妇,剩下的就只能光棍。这就是原子性。在“一夫一妻”制的前提下,女士就具有原子性,男士就相当于原子。)
只有分解为多步操作,多个线程才能对其操作。
有一些不被线程调度器中断的操作,如:
赋值或者return。比如”a = 1;”和 “return a;”这样的操作都具有原子性。
原子性不论是多核还是单核,具有原子性的量,同一时刻只能有一个线程来对它进行操作!
非原子性操作:
类似”a += b”这样的操作不具有原子性,在某些JVM中”a += b”可能要经过这样三个步骤:
(1)取出a和b;
(2)计算a+b;
(3)将计算结果写入内存。
如果有两个线程t1,t2在进行这样的操作。t1在第二步做完之后还没来得及把数据写回内存就被线程调度器中断了,于是t2开始执行,t2执行完毕后t1又把没有完成的第三步做完。这个时候就出现了错误,相当于t2的计算结果被无视掉了。所以上面的买碘片例子在同步add方法之前,实际结果总是小于预期结果的,因为很多操作都被无视掉了。
类似的,像”a++”这样的操作也都不具有原子性。所以在多线程的环境下一定要进行同步操作。
Volatile 变量:
Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。这就是说线程能够自动发现 volatile 变量的最新值 。
Volatile 变量可用于提供线程安全,但是只能应用于非常有限的一组用例:多个变量之间或者某个变量的当前值与修改后值之间没有约束。因此,单独使用
volatile 还不足以实现计数器、互斥锁或任何具有与多个变量相关的不变式(Invariants)的类(例如 “start <=end”)。出于简易性或可伸缩性的考虑,您可能倾向于使用 volatile 变量而不是锁。当使用 volatile
变量而非锁时,某些习惯用法(idiom)更加易于编码和阅读。此外,volatile
变量不会像锁那样造成线程阻塞,因此也很少造成可伸缩性问题。在某些情况下,如果读操作远远大于写操作,volatile 变量还可以提供优于锁的性能优势。
正确使用 volatile 变量的条件
![](/qrcode.jpg)
只能在有限的一些情形下使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:
对变量的写操作不依赖于当前值。
该变量没有包含在具有其他变量的不变式中。
链接:https://www.nowcoder.com/questionTerminal/3f6c5287a9fa4d0baa162e44970a343d来源:牛客网