问题描述 案例代码1中属性没有volatile修饰,主线程修改其值,线程中是看不到其变更的,所以会一直死循环 案例代码2中属性同样没有volatile修饰,但是主线程修改其值,线程中看到了其变更的最新值,线程正常退出。为什么? 案例1:会死循环
  package org.gallant.jitwatch;
  /** * -server -XX:+UnlockDiagnosticVMOptions -XX:+TraceClassLoading -XX:+PrintAssembly -XX:+LogCompilation -XX:+DebugNonSafepoints -XX:LogFile=VisibilityWithoutVolatile.log -Xcomp -XX:CompileCommand=compileonly,*VisibilityWithoutVolatile.* -XX:CompileCommand=dontinline,*VisibilityWithoutVolatile.* * @author 会灰翔的灰机 * @date 2019/10/30 */ public class VisibilityWithoutVolatile extends Thread {     private boolean isRun = true;
      @Override     public void run() {         while(isRun){         }     }     public static void main(String[] args) throws InterruptedException {         VisibilityWithoutVolatile visibility = new VisibilityWithoutVolatile();         visibility.start();         Thread.sleep(1000);         visibility.isRun = false;         System.out.println("stop thread");     } }
  案例2:不会死循环
  package org.gallant.jitwatch;
  /** * -server -XX:+UnlockDiagnosticVMOptions -XX:+TraceClassLoading -XX:+PrintAssembly -XX:+LogCompilation -XX:+DebugNonSafepoints -XX:LogFile=VisibilityWithoutVolatileHavePrint.log -Xcomp -XX:CompileCommand=compileonly,*VisibilityWithoutVolatileHavePrint.* -XX:CompileCommand=dontinline,*VisibilityWithoutVolatileHavePrint.* * @author 会灰翔的灰机 * @date 2019/10/30 */ public class VisibilityWithoutVolatileHavePrint extends Thread {     private boolean isRun = true;
      @Override     public void run() {         while(isRun){             System.out.println(isRun);         }     }     public static void main(String[] args) throws InterruptedException {         VisibilityWithoutVolatileHavePrint visibility = new VisibilityWithoutVolatileHavePrint();         visibility.start();         Thread.sleep(1000);         visibility.isRun = false;         System.out.println("stop thread");     } }
  问题分析 使用javap分析底层字节码 案例1
  public class org.gallant.jitwatch.VisibilityWithoutVolatile extends java.lang.Thread   ... {   public org.gallant.jitwatch.VisibilityWithoutVolatile();     descriptor: ()V     flags: ACC_PUBLIC     Code:       stack=2, locals=1, args_size=1          0: aload_0          1: invokespecial #1                  // Method java/lang/Thread."<init>":()V          4: aload_0          5: iconst_1          6: putfield      #2                  // Field isRun:Z          9: return       LineNumberTable:         line 8: 0         line 9: 4       LocalVariableTable:         Start  Length  Slot  Name   Signature             0      10     0  this   Lorg/gallant/jitwatch/VisibilityWithoutVolatile;
    public void run();     descriptor: ()V     flags: ACC_PUBLIC     Code:       stack=1, locals=1, args_size=1          0: aload_0          1: getfield      #2                  // Field isRun:Z          4: ifeq          10          7: goto          0         10: return       LineNumberTable:         line 13: 0         line 15: 10       LocalVariableTable:         Start  Length  Slot  Name   Signature             0      11     0  this   Lorg/gallant/jitwatch/VisibilityWithoutVolatile;       StackMapTable: number_of_entries = 2         frame_type = 0 /* same */         frame_type = 9 /* same */
    public static void main(java.lang.String[]) throws java.lang.InterruptedException;     descriptor: ([Ljava/lang/String;)V     flags: ACC_PUBLIC, ACC_STATIC     Code:       stack=2, locals=2, args_size=1          0: new           #3                  // class org/gallant/jitwatch/VisibilityWithoutVolatile          3: dup          4: invokespecial #4                  // Method "<init>":()V          7: astore_1          8: aload_1          9: invokevirtual #5                  // Method start:()V         12: ldc2_w        #6                  // long 1000l         15: invokestatic  #8                  // Method java/lang/Thread.sleep:(J)V         18: aload_1         19: iconst_0         20: putfield      #2                  // Field isRun:Z         23: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;         26: ldc           #10                 // String stop thread         28: invokevirtual #11                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V         31: return       LineNumberTable:         line 17: 0         line 18: 8         line 19: 12         line 20: 18         line 21: 23         line 22: 31       LocalVariableTable:         Start  Length  Slot  Name   Signature             0      32     0  args   [Ljava/lang/String;             8      24     1 visibility   Lorg/gallant/jitwatch/VisibilityWithoutVolatile;     Exceptions:       throws java.lang.InterruptedException } 案例2
  public class org.gallant.jitwatch.VisibilityWithoutVolatileHavePrint extends java.lang.Thread   ... {   public org.gallant.jitwatch.VisibilityWithoutVolatileHavePrint();     descriptor: ()V     flags: ACC_PUBLIC     Code:       stack=2, locals=1, args_size=1          0: aload_0          1: invokespecial #1                  // Method java/lang/Thread."<init>":()V          4: aload_0          5: iconst_1          6: putfield      #2                  // Field isRun:Z          9: return       LineNumberTable:         line 8: 0         line 9: 4       LocalVariableTable:         Start  Length  Slot  Name   Signature             0      10     0  this   Lorg/gallant/jitwatch/VisibilityWithoutVolatileHavePrint;
    public void run();     descriptor: ()V     flags: ACC_PUBLIC     Code:       stack=2, locals=1, args_size=1          0: aload_0          1: getfield      #2                  // Field isRun:Z          4: ifeq          20          7: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;         10: aload_0         11: getfield      #2                  // Field isRun:Z         14: invokevirtual #4                  // Method java/io/PrintStream.println:(Z)V         17: goto          0         20: return       LineNumberTable:         line 13: 0         line 14: 7         line 16: 20       LocalVariableTable:         Start  Length  Slot  Name   Signature             0      21     0  this   Lorg/gallant/jitwatch/VisibilityWithoutVolatileHavePrint;       StackMapTable: number_of_entries = 2         frame_type = 0 /* same */         frame_type = 19 /* same */
    public static void main(java.lang.String[]) throws java.lang.InterruptedException;     descriptor: ([Ljava/lang/String;)V     flags: ACC_PUBLIC, ACC_STATIC     Code:       stack=2, locals=2, args_size=1          0: new           #5                  // class org/gallant/jitwatch/VisibilityWithoutVolatileHavePrint          3: dup          4: invokespecial #6                  // Method "<init>":()V          7: astore_1          8: aload_1          9: invokevirtual #7                  // Method start:()V         12: ldc2_w        #8                  // long 1000l         15: invokestatic  #10                 // Method java/lang/Thread.sleep:(J)V         18: aload_1         19: iconst_0         20: putfield      #2                  // Field isRun:Z         23: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;         26: ldc           #11                 // String stop thread         28: invokevirtual #12                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V         31: return       LineNumberTable:         line 18: 0         line 19: 8         line 20: 12         line 21: 18         line 22: 23         line 23: 31       LocalVariableTable:         Start  Length  Slot  Name   Signature             0      32     0  args   [Ljava/lang/String;             8      24     1 visibility   Lorg/gallant/jitwatch/VisibilityWithoutVolatileHavePrint;     Exceptions:       throws java.lang.InterruptedException }
  除了多出几行指令外没有什么进展。。。
  使用hsdis与jitwatch分析机器指令 案例1 <ignore_js_op>![]()  案例2 <ignore_js_op>![]() 
  可以看到除了多出两个safepoint之外没有其他不同,并且safepoint类型不同,具体原因还是没能找到答案,只能查看对应的汇编代码含义再继续分析原因 | 
 
 
 
 
 
 |