• 引用赋值的原子性问题


    • 一、问题及来源
    • 二、分析
      • 2.1 官方引证
      • 2.2 过程分析

    一、问题及来源

    对原始类型不包括(long,double)变量进行赋值是原子操作,但是没有找到资料对引用类型的变量的赋值操作的原子性进行说明.例如 Object var = otherObjectValue; 这是原子操作吗?

    最近在看并发编程,此问题由int[] arr = new int[0]是不是原子操作而引出。

    二、分析

    2.1 官方引证

    向 reference 赋值是原子的(obj = otherObjectValue):

    https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.7

    2.2 过程分析

    我认为是原子操作 ,声明立刻赋值和赋值是等价的(Object var = objValue; 和 var = objValue 等价):

    K k = source;

    K k;
    k = source;

    编译出的字节码是一样的;(使用 javap -c):

    class K {
     
        private int c;
        public int getC() {
            return c;
        }
        public void setC(int c) {
            this.c = c;
        }
    }
    class T {
        public static void main(String[] args) {
            K source = new K();
            K k = source;
            k.getC();
        }
    }
    T的字节码 折叠原码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    Compiled from "T.java"
     
    class T {
      T();
        Code:
           0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4return
      public static void main(java.lang.String[]);
        Code:
           0new           #2                  // class K, new K() start
           3: dup
           4: invokespecial #3                  // Method K."<init>":()V
           7: astore_1                          // source = new K()
           8: aload_1                           // new K() end, prepare `source`
           9: astore_2                          // k = source;
          10: aload_2                           // prepare `k`
          11: invokevirtual #4                  // Method K.getC:()I
          14: pop
          15return
    }
    class T2 {
        public static void main(String[] args) {
            K source = new K();
            K k;
            k = source;
            k.getC();
        }
    }
    T1的字节码 折叠原码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    Compiled from "T2.java"
    class T2 {
      T2();
        Code:
           0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4return
      public static void main(java.lang.String[]);
     
        Code:
           0new           #2                  // class K
           3: dup
           4: invokespecial #3                  // Method K."<init>":()V
           7: astore_1
           8: aload_1
           9: astore_2
          10: aload_2
          11: invokevirtual #4                  // Method K.getC:()I
          14: pop
          15return
    }
    class T2 {
        public static void main(String[] args) {
            K source = new K();
            K k;
            k = source;
            k.getC();
        }
    }
    T2的字节码 折叠原码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    Compiled from "T3.java"
    class T3 {
      static K k;
      T3();
        Code:
           0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4return
      public static void main(java.lang.String[]);
        Code:
           0new           #2                  // class K
           3: dup
           4: invokespecial #3                  // Method K."<init>":()V
           7: astore_1
           8: aload_1
           9: putstatic     #4                  // Field k:LK;
          12: getstatic     #4                  // Field k:LK;
          15: invokevirtual #5                  // Method K.getC:()I
          18: pop
          19return
    }

    由 T1 和 T2 ,声明一个 reference 并立刻赋值( Object obj = otherObjectValue )是原子的。

    在字节码里是 2 句指令 `aload`和`astore`,但是这两句根据上面提到的 JLS ,原子性是有保证的:

    1. k = source 等价于
        ```
       8: aload_1 // source 压栈
       9: astore_2 // source 出栈给 k
       ```
    2. k = source 是 reference 赋值
    3. reference 赋值根据 JLS ,是原子的
        => 用于 reference 赋值的`aload + astore`是原子的。

  • 相关阅读:
    JZOJ.2117. 【2016-12-30普及组模拟】台风
    团队合作
    长沙游记
    统计
    html....
    OI之路
    三鑫普及组模拟赛
    牛顿迭代法
    台风
    gcd
  • 原文地址:https://www.cnblogs.com/chenmingming0225/p/12922289.html
Copyright © 2020-2023  润新知