温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java自增操作的原子性是什么

发布时间:2021-10-29 16:07:55 来源:亿速云 阅读:195 作者:柒染 栏目:编程语言

这期内容当中小编将会给大家带来有关Java自增操作的原子性是什么,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

最近在工作中和一个同事因为自增是不是原子性操作争论的面红耳赤,那Java的自增操作到底是不是原子性操作呢,答案是否的,即Java的自增操作不是原子性操作。

1.首先我们先看看Bruce Eckel是怎么说的:

In the JVM an increment is not atomic and involves both a read and a write. (via the latest Java Performance Tuning Newsletter)

意思很简单,就是说在jvm中自增不是原子性操作,它包含一个读操作和一个写操作。

2.以上可能还不能让你信服,要想让人心服口服,就必须用代码说话。正如FaceBook的文化一样:代码赢得争论。那我们就看一段代码:

以下的代码是用100个线程同时执行自增操作,每个线程自增100次,如果自增操作是原子性操作的话,那么执行完amount的值为10,000。运行代码之后,你会发现amount的值小于10,000,这就说明自增操作不是原子性的

/**   *    * @author renrun.wu   */ 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);      }  }

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

以下是一个简单的自增操作代码

public class Increment {      private int id = 0;       public void getNext(){          id++;      }  }

我们看看反编译之后的Java字节码,主要关注getNext()方法内部的Java字节码。

public class Increment extends java.lang.Object{      public Increment();        Code:  :   aload_0  :   invokespecial   #1; //Method java/lang/Object."<init>":()V  :   aload_0  :   iconst_0  :   putfield        #2; //Field id:I  :   return      public void getNext();        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      }

很明显,我们能够看到在getNext()方法内部,对于类变量id有一个先取值后加一再赋值的过程。因此,我们可以很肯定的说Java中的自增操作不是原子性的。

4.也许你会问,那局部变量的自增操作是否是原子性的。好,我们在看看一下代码:

public class Increment {      public void getNext(){      int id = 0;          id++;      }  }

我们再看看反编译之后的Java字节码,主要还是关注getNext()方法内部的Java字节码。

public class Increment extends java.lang.Object{  public Increment();    Code:  :   aload_0  :   invokespecial   #1; //Method java/lang/Object."<init>":()V  :   return  public void getNext();    Code:  :   iconst_0  :   istore_1  :   iinc    1, 1 :   return  }

与全局变量的自增操作相比,很明显局部变量的自增操作少了getfield与putfield操作。而且对于局部变量来说,它无论如何都不会涉及到多线程的操作,因此局部变量的自增操作是否是原子操作也就显得不那么重要了。

上述就是小编为大家分享的Java自增操作的原子性是什么了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注亿速云行业资讯频道。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI