java+自增对象,关于Java自增操作的原子性

最近在中和一个同事因为自增是不是原子性操作争论的面红耳赤,那的自增操作到底是不是原子性操作呢,答案是否的,即Java的自增操作不是原子性操作。51Testing软件测试网8a7st"`|^w2Dk

1、首先我们先看看Bruce Eckel是怎么说的:51Testing软件测试网'ct7W4n6Q2QN51Testing软件测试网T$p{Ks4g S

In the JVM an increment is not atomic and involves both a read and a

write. (via the latest Java Performance Tuning Newsletter).G-{Hl[b+Kz051Testing软件测试网woQ%G-e4f

意思很简单,就是说在jvm中自增不是原子性操作,它包含一个读操作和一个写操作。51Testing软件测试网2TF(VsPtK51Testing软件测试网`R)Z'R*B

2、以上可能还不能让你信服,要想让人心服口服,就必须用代码说话。正如FaceBook的文化一样:代码赢得争论。那我们就看一段代码:/Y"~{0J:e]%r$@0

{,B$Y1Y,Ybg*T0以下的代码是用100个线程同时执行自增操作,每个线程自增100次,如果自增操作是原子性操作的话,那么执行完amount的值为10,000。运行代码之后,你会发现amount的值小于10,000,这就说明自增操作不是原子性的"N&t^.l-x)M`6eZ0/**

*

* @author renrun.wu

*/

publicclassMultiThreadimplementsRunnable {

privateintcount;

privateintamount =1;

publicMultiThread() {

count =100;

}

publicMultiThread(intcount) {

this.count = count;

}

@Override

publicvoidrun() {

for(inti =0; i 

amount++;

}

}

publicstaticvoidmain(String[] args) {

ExecutorService executorService = Executors.newCachedThreadPool();

MultiThread multiThread =newMultiThread();

for(inti =0; i <100; i++) {

executorService.execute(multiThread);

}

executorService.shutdown();

try{

Thread.sleep(60000);

}catch(InterruptedException e) {

e.printStackTrace();

}

System.out.println(multiThread.amount);

}

}51Testing软件测试网aX5mL!W&ng0W

3、如果以上还不能让你信服的话,也没关系。我们就把自增操作反编译出来,看看java字节码是怎么操作的's O&jpUz o2Czc@0

c,|-{H$o.BnB0以下是一个简单的自增操作代码fIo9g2W"o4QV3|*q0publicclassIncrement {

privateintid =0;

FUlU*h@"Nv$`0

publicvoidgetNext(){

id++;

}

}

我们看看反编译之后的Java字节码,主要关注getNext()方法内部的Java字节码。51Testing软件测试网@,JsbhL

51Testing软件测试网1h+j^!^1u%PGY

{hpublicclassIncrementextendsjava.lang.Object{

publicIncrement();

Code:

:   aload_0

:   invokespecial   #1;//Method java/lang/Object."":()V

:   aload_0

:   iconst_0

:   putfield        #2;//Field id:I

:return

publicvoidgetNext();

Code:

:   aload_0//加载局部变量表index为0的变量,在这里是this

:   dup//将当前栈顶的对象引用复制一份

:   getfield        #2;//Field id:I,获取id的值,并将其值压入栈顶

:   iconst_1//将int型的值1压入栈顶

:   iadd//将栈顶两个int类型的元素相加,并将其值压入栈顶

:   putfield        #2;//Field id:I,将栈顶的值赋值给id

:return

}51Testing软件测试网_U0GC:v

很明显,我们能够看到在getNext()方法内部,对于类变量id有一个先取值后加一再赋值的过程。因此,我们可以很肯定的说Java中的自增操作不是原子性的。&T5m-d3F2Y051Testing软件测试网Gs!n{d/v|$z#ZA

4、也许你会问,那局部变量的自增操作是否是原子性的。好,我们在看看一下代码:VP1|H]t1C6r[MB0

zNSXvE6v051Testing软件测试网

w+?.v`~'XrDZ)Z+W WpublicclassIncrement {

publicvoidgetNext(){

intid =0;

id++;

}

}51Testing软件测试网BJ,f^

L4q8k

我们再看看反编译之后的Java字节码,主要还是关注getNext()方法内部的Java字节码。51Testing软件测试网6te] J-R

up

e1f0K'x$zGxh,B051Testing软件测试网%VO,c$zd/er&hpublicclassIncrementextendsjava.lang.Object{

publicIncrement();

Code:

:   aload_0

:   invokespecial   #1;//Method java/lang/Object."":()V

:return

publicvoidgetNext();

Code:

:   iconst_0

:   istore_1

:   iinc1,1

:return

}

:ub`+?@'JB2j-w0与全局变量的自增操作相比,很明显局部变量的自增操作少了getfield与putfield操作。而且对于局部变量来说,它无论如何都不会涉及到多线程的操作,因此局部变量的自增操作是否是原子操作也就显得不那么重要了。)f;h3M;dSS0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值