在没同步前,怎么会输出取款余额800后紧接着Bank的toString余额是1100?

在没同步前,怎么会输出取款余额800后紧接着Bank的toString余额是1100?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//有一种运行结果如下:
//存款后的账户余额为:1100
//取款后的账户余额:800
//Bank [账号:1001,余额:1100]
 
 
package bank;
 
public class Bank {
 
    private String account; // 账号
    private int balance; // 账户余额
 
    public Bank(String account, int balance) {
        this.account = account;
        this.balance = balance;
    }
 
    public String getAccount() {
        return account;
    }
 
    public void setAccount(String account) {
        this.account = account;
    }
 
    public int getBalance() {
        return balance;
    }
 
    public void setBalance(int balance) {
        this.balance = balance;
    }
 
    @Override
    public String toString() {
        return "Bank [账号:" + account + ",余额:" + balance + "]";
    }
 
    // 存款
 
    public void saveAccount() {
        // 可以在不同的位置处添加sleep方法
        // 获取当前的账号余额
        int balance = getBalance();
        try {
            Thread.sleep(1000);
        catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 修改余额,存100元
        balance += 100;
        // 修改账户余额
        setBalance(balance);
        // 输出存款后的账户余额
        System.out.println("存款后的账户余额为:" + balance);
    }
 
    // 取款
    public void drawAccout() {
 
        // 获得当前的账户余额
        int balance = getBalance();
        // 修改余额,取200
        balance = balance - 200;
        try {
            Thread.sleep(1000);
        catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 修改账户余额
        setBalance(balance);
        System.out.println("取款后的账户余额:" + balance);
    }
}
 
 
package bank;
 
//存款
public class SaveAccount implements Runnable {
    Bank bank;
 
    public SaveAccount(Bank bank) {
        this.bank = bank;
    }
 
    @Override
    public void run() {
        bank.saveAccount();
    }
 
}
 
 
package bank;
 
//取款
public class DrawAccount implements Runnable {
    Bank bank;
 
    public DrawAccount(Bank bank) {
        this.bank = bank;
    }
 
    @Override
    public void run() {
        bank.drawAccout();
    }
 
}
 
 
package bank;
 
public class Test {
 
    public static void main(String[] args) {
        // 创建账户,给定余额1000
        Bank bank = new Bank("1001"1000);
        // 创建线程对象
        SaveAccount sa = new SaveAccount(bank);
        DrawAccount da = new DrawAccount(bank);
        // 创建线程对象,实现Runnable的类对象作为参数传入
        Thread save = new Thread(sa);
        Thread draw = new Thread(da);
        save.start();
        draw.start();
        // 加join方法的目的是想让打印输出bank的tostiring方法最后一个输出;
        try {
            save.join();
            draw.join();
        catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(bank);
 
    }
 
}


正在回答

登陆购买课程后可参与讨论,去登陆

6回答

同学你好,这里你可以这样理解,这里存款与取款都是一个线程,操作的对象没有加锁,而这两个线程是同时执行的,所以最后main方法中调用的toString方法输出的对象是随机的,可能是存款的线程中的也有可能是取款的线程中的哟,因为那是两个同时执行的线程!

所以最后输出的toString中的对象可能是取款线程中的结果,也有可能是存款线程中的结果!

如果我的回答解决了你的疑惑,请采纳。祝:学习愉快~


提问者 慕哥5118177 2019-06-10 19:30:01

//存款后的账户余额为:1100

//取款后的账户余额:800

//Bank [账号:1001,余额:1100]

我不理解这样的运行结果,请老师解惑!

提问者 慕哥5118177 2019-06-10 19:28:51

老师,你说的我明白。

但是这不能解释,为什么最后bank的toString余额还是第一步存款后的余额1100?为什么不是第二步取款后的余额800?

这里,第二步输出取款后余额800,说明余额已更新为800,而且存款和取款线程都运行完了,

第二步和第三步的余额不一样,要怎么理解?

我无法模拟程序的运行步骤,老师能具体说一下程序具体步骤吗?

好帮手慕小班 2019-06-10 10:39:16

同学你好,在没有同步前的测试方法中,创建两个线程,这两个线程同时获取到一个Bank对象,这时两个线程获取对象的内容都是编号1001,金额1000,然后线程调用各自的方法,进行金额的加或者减,所以最后线程对应的值会出现余额为800和余额为1100!

http://img1.sycdn.imooc.com//climg/5cfdc17700015aef04050082.jpg

这是因为线程并没有加锁,当第一个线程操作时,第二个线程同时进行操作,获取的是同一个对象,当操作完成后,输出的是线程对应操作完成后的值,所以会出现不同的操作值!

如果我的回答解决了你的疑惑,请采纳。祝:学习愉快~

  • 提问者 慕哥5118177 #1
    老师,你说的我明白。但是这不能解释,为什么最后bank的toString余额还是第一步存款后的余额1100?为什么不是第二步取款后的余额800?这里,第二步输出取款后余额800,说明余额已更新为800,而且存款和取款线程都运行完了,第二步和第三步的余额不一样,要怎么理解?我无法模拟程序的运行步骤,老师能具体说一下程序具体步骤吗?
    2019-06-10 19:28:24
提问者 慕哥5118177 2019-06-10 01:24:28

老师,

我举的例子中,第二步能输出取款后余额800,说明余额已更新为800,那为什么最后bank的toString余额还是第一步存款后的余额1100?为什么不是第二步取款后的余额800?

第二步和第三步的余额不一样,要怎么理解?

如果第二步和第三步显示的值一样,我是理解的。

好帮手慕小班 2019-06-09 17:39:46

同学你好,这里没有加同步,首先每个线程都获取到了而同一个对象内容

       // 创建账户,给定余额1000

        Bank bank = new Bank("1001", 1000);

都获取到了账户余额是1000元,调用取款方法,余额减去200     调用存款方法,余额加上100

这两个线程有随机性,多运行几次,就会出现不同的结果,例如

http://img1.sycdn.imooc.com//climg/5cfcd3aa000118f807630633.jpg

http://img1.sycdn.imooc.com//climg/5cfcd3c8000140f409040653.jpg

所以这里是线程随机的哦!

如果我的回答解决了你的疑惑,请采纳。祝:学习愉快~

  • 提问者 慕哥5118177 #1
    老师, 我举的例子中,第二步能输出取款后余额800,说明余额已更新为800,那为什么最后bank的toString余额还是第一步存款后的余额1100?为什么不是第二步取款后的余额800? 第二步和第三步的余额不一样,要怎么理解? 如果第二步和第三步显示的值一样,我是理解的。
    2019-06-10 01:24:55
问题已解决,确定采纳
还有疑问,暂不采纳

恭喜解决一个难题,获得1积分~

来为老师/同学的回答评分吧

0 星
请稍等 ...
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号

在线咨询

领取优惠

免费试听

领取大纲

扫描二维码,添加
你的专属老师
插入代码