java之线程可见性分析

问题描述
案例代码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

案例2


可以看到除了多出两个safepoint之外没有其他不同,并且safepoint类型不同,具体原因还是没能找到答案,只能查看对应的汇编代码含义再继续分析原因
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值