一、故事引入
80年代,小明和小红恋爱多年,准备结婚。于是两个人打拼多年,积攒了1万块钱的结婚基金,并且决定把它存放在银行。由于当时没有手机等通信设备,所以在两个人中,有其中一个人去取钱,另外一个人是不知道的。后来,小明迷上了追星,从银行里取出了1千块钱,于是卡里就剩下了9千块钱。这个时候,小红是不知道的,她依然觉得银行卡里有一万块钱。
二、实现思路
小明类:多线程类,睡眠10毫秒,等线程醒来后,修改金额为9千,为了使得修改效果明显,当小明修改完后,打印出 “ 金额已经被修改了 ”
小红类:多线程类,循环判断金额是否为1万,若不是,则打印 “ 金额不是1万了 ”
存款类:普通类,定义一个共享数据money,(public static int money=10000)
三、代码实现
小明类:
public class XiaoMing extends Thread{
@Override
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
Money.money = 1000;
// 为了让运行效果明显一点,输出小明修改
System.out.println("金额已经被修改了");
}
}
小红类:
public class XiaoHone extends Thread{
@Override
public void run() {
while (Money.money==10000){
}
System.out.println("金额不是1万了");
}
}
存款类:
public class Money {
public static int money = 10000;
}
测试类:
public class DemoTest {
public static void main(String[] args) {
XiaoHone xh = new XiaoHone();
XiaoMing xm = new XiaoMing();
xh.start();
xm.start();
}
}
运行结果:
我们看到了,在小明类中,已经修改了共享数据的金额了。但是,程序还在运行,小红类也没有输出结果。
四、问题分析
共享数据是存放在堆里的,当线程访问共享数据时,会复制一份共享数据存放在自己的线程栈中,当修改完成之后,会将自己线程栈中的数据进行修改,然后将线程栈中的数据赋值到堆数据里面去。但是如果线程没有对数据进行修改,那么他就会一直使用自己线程栈中的数据,即使堆数据修改了。
五、volatile关键字
volatile强制线程使用线程栈数据之前,获取堆里的共享数据,修改存储类,其他类不变:
public class Money {
public static volatile int money = 10000;
}
运行结果:
我们就达到了预期的结果了,程序也结束了,效果也出来了。
六、synchronized 同步代码块
同样的问题,我们使用 synchronized 也可以解决这类问题,通过锁可以使得每个线程执行之前都要获取一次共享数据。实现代码如下图所示:
小明类:
public class XiaoMing extends Thread{
@Override
public void run() {
synchronized (Money.obj){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
Money.money = 1000;
System.out.println("金额已经被修改了");
}
}
}
小红类:
public class XiaoHone extends Thread{
@Override
public void run() {
while (true){
synchronized (Money.obj){
if (Money.money!=10000){
System.out.println("金额不是1万了");
break;
}
}
}
}
}
存储类:
public class Money {
public static int money = 10000;
public static Object obj = new Object();
}
测试类:
public class DemoTest {
public static void main(String[] args) {
XiaoHone xh = new XiaoHone();
XiaoMing xm = new XiaoMing();
xh.start();
xm.start();
}
}
运行结果:
好了,这就是结婚基金的问题!如果觉得有用的话,点个赞再走吧!