Java多线程 之 原子性与可见性(八)
2016-11-06 10:41
225 查看
1.原子性
Java中的原子性,是指:原子操作是不能被线程调度机制中断的;操作一旦开始,它一定会在可能发生的“上下文切换”(即切换到其他线程执行)之前执行完毕。 但是千万不要认为“原子操作不需要同步控制(这是错误的)”!
原子性可以应用于除long和double之外的基本类型的简单操作(赋值和返回值)。long和double这种64位的数据类型,在JVM内部是通过两条32位的操作完成的,因此有可能发生上下文切换。如果给long和double变量加上volatile关键字也可以获得原子性。
但是原子性并不能保证并发的代码的正确性。比如,在多处理器(可能是单处理器但是多核)多线程环境下,一个线程对某一变量的写入操作有可能只是将这种变化存在了CPU缓存中,而其他线程对该变量的访问只是局限在各自的CPU缓存,这样导致了不一致性。因此,还需要使用volatile关键字来保证可见性,将变量的修改直接写入到内存中。
当然同步(加锁)机制也可以保证这种可见性,将变量的修改直接写到内存中。
在同一个任务中,可见性问题是不存在的。即该任务对变量的修改,该任务肯定知道。
但是,当一个属性的值依赖于它之前的值时(如递增操作),一个属性的值依赖于其他域的值的限制,volatile就无法工作了。这里说的不能工作了,应该是指在并发环境下无法保证代码的正确性吧。
我的理解:原子性+volatitle可以保证并发的正确性。但是,最好编码时还是尽量用 同步加锁 来保证并发的正确性。第一选择应该是synchronized关键字。
再次声明:在Java中,自增操作不是原子的。
在《Thinking in java》第四版中文版的682-684页举例详细说明下面两点:
(1)在java中,对除long和double之外的基本类型的简单操作(赋值、返回值)是原子性的,但是无法保证并发的正确性。
(2)在java中,递增操作不是原子性的,会引发并发问题。
2.原子类Atomic
在JDK5之后,引入了AtomicInteger、AtomicLong、AtomicReference等原子类。这些类其实是用来构建java.util.concurrent中的类的。也就是说,这些类是JUC实现的基础类,JUC构建在Atomic之上,JUC的并发是用Atomic来实现的。 我们在写代码时,要首先考虑使用synchronized关键字和Lock对象,而避免使用Atomic类。当涉及到调优时,可以考虑使用Atomic类。Atomic类要比synchronized、Lock更高效。
下面使用Atomic类来重写EvenGenerator:
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">package</span> org.fan.learn.thread.share; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.util.Timer; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.util.TimerTask; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> java.util.concurrent.atomic.AtomicInteger; <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * Created by thinkpad on 2016/6/19. */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">AtomicEvenGenerator</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">IntGenerator</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> AtomicInteger atomicInteger = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> AtomicInteger(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> <span class="hljs-title" style="box-sizing: border-box;">next</span>() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> atomicInteger.addAndGet(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">main</span>(String[] args) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Timer().schedule(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> TimerTask() { <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">run</span>() { System.err.println(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Aborting"</span>); System.exit(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); } }, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5000</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//执行5s后自动终止</span> EvenChecker.test(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> AtomicEvenGenerator()); } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li></ul>
这里使用Timer,使程序运行5s之后自动终止。
运行结果如下:
Press control-c to exit
Aborting
关于EvenGenerator的其他部分可参考下面两篇博文:
Java多线程 之 访问共享资源(六)
Java多线程 之 访问共享资源synchronized、lock(七)
相关文章推荐
- Java多线程中的内存可见性与原子性分析
- java多线程学习笔记2---理解原子性和可见性
- Java之多线程内存可见性_2(volatile不能保证原子性)
- Java多线程之内存可见性与原子性总结
- Java多线程 之 原子性与可见性(八)
- Java多线程总结(5)— 原子性、可见性、有序性和并发库的原子性操作
- Java多线程之内存可见性
- Java 线程概述: 线程种类、状态,原子性、内存可见性、synchronized、volatile
- [Java 多线程] 变量可见性
- Java的多线程之同步篇三:同步阻塞、监视器、volatile、final、原子性、线程局部变量、锁测试与超时、读写锁
- Java之多线程内存可见性_2(volatile实现可见性)
- Java同步——可见性和原子性
- Java多线程之内存可见性
- Java多线程之内存可见性
- 多线程、锁,可重入,同步,原子性,可见性,非阻塞算法
- Java之多线程内存可见性_3(synchronized和volatile比较)
- java-多线程深入(二)互斥性和可见性
- 深入理解Java虚拟机笔记---原子性、可见性、有序性
- JAVA多线程之内存可见性笔记
- java多线程之内存可见性学习笔记