关于Java自增操作的原子性
上一篇 /
下一篇 2012-05-25 09:12:43
/ 个人分类:Java
最近在工作中和一个同事因为自增是不是原子性操作争论的面红耳赤,那Java的自增操作到底是不是原子性操作呢,答案是否的,即Java的自增操作不是原子性操作。51Testing软件测试网-u9b&X0Ju1rc*E 1、首先我们先看看Bruce Eckel是怎么说的:
L7Lp+{3~m]a051Testing软件测试网/{r@
U2j5UG
In the JVM an increment is not atomic and involves both a read and a
write. (via the latest Java Performance Tuning Newsletter)
9_4PJ1Hu)p.VQ"M6K04R*c EdK}y+KW^,t0 意思很简单,就是说在jvm中自增不是原子性操作,它包含一个读操作和一个写操作。51Testing软件测试网|BF dS
51Testing软件测试网x6rt3| o
V#p)F9H r 2、以上可能还不能让你信服,要想让人心服口服,就必须用代码说话。正如FaceBook的文化一样:代码赢得争论。那我们就看一段代码:
K[,BF
D&h5e`0HU)g&u3[u8z.OyN0 以下的代码是用100个线程同时执行自增操作,每个线程自增100次,如果自增操作是原子性操作的话,那么执行完amount的值为10,000。运行代码之后,你会发现amount的值小于10,000,这就说明自增操作不是原子性的
T#x+Y&u~el s0-
-
-
-
- public class MultiThread implements Runnable {
- private int count;
- private int amount = 1;
-
- public MultiThread() {
- count = 100;
- }
-
- public MultiThread(int count) {
- this.count = count;
- }
-
- @Override
- public void run() {
- for (int i = 0; i < count; i++) {
- amount++;
- }
- }
-
- public static void main(String[] args) {
- ExecutorService executorService = Executors.newCachedThreadPool();
- MultiThread multiThread =new MultiThread();
- for (int i = 0; i < 100; i++) {
- executorService.execute(multiThread);
- }
- executorService.shutdown();
-
- try {
- Thread.sleep(60000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println(multiThread.amount);
- }
- }
|
51Testing软件测试网3zmDQ+Y 3、如果以上还不能让你信服的话,也没关系。我们就把自增操作反编译出来,看看java字节码是怎么操作的
:oh^ R
S&xb051Testing软件测试网#Y/o/ISo 以下是一个简单的自增操作代码
2E?4rb5^m.S|0- public class Increment {
- private int id = 0;
Pm PAOZ#Zl)T0- public void getNext(){
- id++;
- }
- }
- 我们看看反编译之后的Java字节码,主要关注getNext()方法内部的Java字节码。
]KmaI_x+~/zl051Testing软件测试网 xd;G7JTG
t2yE
- public class Increment extends java.lang.Object{
- public Increment();
- Code:
- : aload_0
- : invokespecial #1;
- : aload_0
- : iconst_0
- : putfield #2;
- : return
-
- public void getNext();
- Code:
- : aload_0
- : dup
- : getfield #2;
- : iconst_1
- : iadd
- : putfield #2;
- : return
-
- }
|
oU$`z\
J*c%e7O0 很明显,我们能够看到在getNext()方法内部,对于类变量id有一个先取值后加一再赋值的过程。因此,我们可以很肯定的说Java中的自增操作不是原子性的。51Testing软件测试网$q%g1oKx
'q |$ZA0`V+cm7[0 4、也许你会问,那局部变量的自增操作是否是原子性的。好,我们在看看一下代码:51Testing软件测试网Cs6X w6\Pp
51Testing软件测试网*M1j$bo9oE/xz
[&VSd|9O0V1R3U0- public class Increment {
- public void getNext(){
- int id = 0;
- id++;
- }
- }
|
}i onv a i0 我们再看看反编译之后的Java字节码,主要还是关注getNext()方法内部的Java字节码。
@cZTk~ D051Testing软件测试网T}3q`Sqs&xM51Testing软件测试网M g;BW!jo6B~^$g3I
- public class Increment extends java.lang.Object{
- public Increment();
- Code:
- : aload_0
- : invokespecial #1;
- : return
-
- public void getNext();
- Code:
- : iconst_0
- : istore_1
- : iinc 1, 1
- : return
-
- }
|
-KQU?J7PFy0 与全局变量的自增操作相比,很明显局部变量的自增操作少了getfield与putfield操作。而且对于局部变量来说,它无论如何都不会涉及到多线程的操作,因此局部变量的自增操作是否是原子操作也就显得不那么重要了。51Testing软件测试网*D-q+@9a!F$Jm [*`'U9^0_
收藏
举报
TAG: