Java多线程Sample 1

源码地址在github的ThreadsSafeProblem仓库demo1包

一、问

内存中有一个整型变量value=0,两个线程都获取它后,将变量自加,会输出什么结果?

二、代码

UnsafeSequence.java
package demo1;

public class UnsafeSequence {
    private int value;

    public int getNextVal(){
        return value++;
    }
}
MyRunnable.java
package demo1;

public class MyRunnable implements Runnable {
    UnsafeSequence unsafeSequence;
    //向线程注入公用对象
    public MyRunnable(UnsafeSequence unsafeSequence) {
        this.unsafeSequence = unsafeSequence;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+":"+unsafeSequence.getNextVal());
    }
}
Main.java
package demo1;

public class Main {
    public static void main(String[] args) {
        //定义公用对象
        UnsafeSequence unsafeSequence = new UnsafeSequence();
        //定义两个线程
        MyRunnable m1 = new MyRunnable(unsafeSequence);
        MyRunnable m2 = new MyRunnable(unsafeSequence);
        Thread t1 = new Thread(m1);
        Thread t2 = new Thread(m2);
        //启动线程
        t1.start();
        t2.start();
    }
}

三、选项

看完代码后,你觉得会输出什么呢?

  • A. t1:0 和 t2:1
  • B. t1:0 和 t2:0
  • C. t1:1 和 t2:0
  • D. t2:0 和 t1:1
  • E. t2:0 和 t1:0
  • F. t2:1 和 t1:0

答案:ABCDEF

四、分析原因

UnsafeSequence类中的value++操作,执行的过程中,大概可以分为取数、操作、写回3个操作,由于两个线程的这三个操作顺序的不确定性,所以上面程序输出的结果也有所不同。

Created with Raphaël 2.1.0 取出value value++ 写回value

如图这种状况,输出结果为t1:0 t2:0,至于其它情况可以多允许几次,估计就能看到不同的结果。
这里写图片描述

五、通过字节码分析

使用javap -v UnsafeSequence.class反编译查看字节码:

{
  public demo1.UnsafeSequence();
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #10                 // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0       5     0  this   Ldemo1/UnsafeSequence;

  public int getNextVal();
    flags: ACC_PUBLIC
    Code:
      stack=4, locals=1, args_size=1
         0: aload_0
         1: dup
         2: getfield      #18                 // Field value:I
         5: dup_x1
         6: iconst_1
         7: iadd
         8: putfield      #18                 // Field value:I
        11: ireturn
      LineNumberTable:
        line 7: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      12     0  this   Ldemo1/UnsafeSequence;
}

可以很清楚的看到,getNextVal方法做的0-11的操作,如果t1的putfield执行在t2的aload_0后,则t1/t2输出的结果都为0,否则一个为0一个为1。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MEMORYLORRY

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值