浅谈Java中的atomic包实现原理及应用-创新互联

1.同步问题的提出

称多网站建设公司创新互联,称多网站设计制作,有大型网站制作公司丰富经验。已为称多成百上千提供企业网站建设服务。企业网站搭建\外贸网站制作要多少钱,请找那个售后服务好的称多做网站的公司定做!

假设我们使用一个双核处理器执行A和B两个线程,核1执行A线程,而核2执行B线程,这两个线程现在都要对名为obj的对象的成员变量i进行加1操作,假设i的初始值为0,理论上两个线程运行后i的值应该变成2,但实际上很有可能结果为1。

我们现在来分析原因,这里为了分析的简单,我们不考虑缓存的情况,实际上有缓存会使结果为1的可能性增大。A线程将内存中的变量i读取到核1算数运算单元中,然后进行加1操作,再将这个计算结果写回到内存中,因为上述操作不是原子操作,只要B线程在A线程将i增加1的值写回到内存之前,读取了内存中i的值(此时i值为0),那么一定就会出现i的结果为1。因为A和B线程读取的i的值都为0,两个线程对它加1后的值都为1,两个线程先后将1写入到变量i中,也就是说i被两次写入的值都为1。

最通常的解决方法是两个线程中对i加1的代码用synchronize关键字对obj对象加锁。今天我们介绍一种新的解决方案,即使用Atomic包中的相关类来解决。

2.Atomic在硬件上的支持

在单处理器系统(UniProcessor)中,能够在单条指令中完成的操作都可以认为是"原子操作",因为中断只能发生于指令之间(因为线程的调度需要通过中断完成)。这也是某些CPU指令系统中引入了test_and_set、test_and_clear等指令用于临界资源互斥的原因。在对称多处理器(SymmetricMulti-Processor)结构中就不同了,由于系统中有多个处理器在独立地运行,即使能在单条指令中完成的操作也有可能受到干扰。

在x86平台上,CPU提供了在指令执行期间对总线加锁的手段。CPU芯片上有一条引线#HLOCKpin,如果汇编语言的程序中在一条指令前面加上前缀"LOCK",经过汇编以后的机器代码就使CPU在执行这条指令的时候把#HLOCKpin的电位拉低,持续到这条指令结束时放开,从而把总线锁住,这样同一总线上别的CPU就暂时不能通过总线访问内存了,保证了这条指令在多处理器环境中的原子性。当然,并不是所有的指令前面都可以加lock前缀的,只有ADD,ADC,AND,BTC,BTR,BTS,CMPXCHG,DEC,INC,NEG,NOT,OR,SBB,SUB,XOR,XADD,和XCHG指令前面可以加"LOCK"指令,实现原子操作。

Atomic的核心操作就是CAS(compareandset,利用CMPXCHG指令实现,它是一个原子指令),该指令有三个操作数,变量的内存值V(value的缩写),变量的当前预期值E(exception的缩写),变量想要更新的值U(update的缩写),当内存值和当前预期值相同时,将变量的更新值覆盖内存值,执行伪代码如下。

if(V == E){ 
  V = U 
  return true 
}else{ 
  return false 
}

标题名称:浅谈Java中的atomic包实现原理及应用-创新互联
网站地址:http://ybzwz.com/article/dscgii.html