今天java群里一个网友问了一个多线程的问题,代码我简化一下如下BankCard.java
public class BankCard {private int num;
public int getNum() {return num;}
public void setNum(int num) {this.num = num;}}
Father.java
public class Father implements Runnable {
private BankCard bc;private int temp;
public Father(BankCard bc) {this.bc = bc;}
public void run() {
temp = bc.getNum();
while (true) {
synchronized (bc) {if (temp <= 5000) {temp = bc.getNum();System.out.println(temp + “………..”);temp += 1500;bc.setNum(temp);System.out.println(“父親放進了1500,现在剩余+” + temp);} elseThread.yield();
}
}
}}GrandFather.java
public class GrandFather implements Runnable {
private int temp ;private BankCard bc;public GrandFather(BankCard bc){this.bc = bc;}public void run() {temp = bc.getNum();
while(true){
synchronized (bc) {
if (temp <= 5000) {temp = bc.getNum();temp += 800;bc.setNum(temp);System.out.println(“爺爺放進了800钱,现在剩余+”+temp);}elseThread.yield();}}
}
}Mother.java
public class Mother implements Runnable {
private int temp;
private BankCard bc;public Mother(BankCard bc){this.bc = bc;}
public void run() {temp = bc.getNum();while (true) {
synchronized (bc) {if (temp <= 5000) {temp = bc.getNum();temp += 1200;bc.setNum(temp);System.out.println(“母親存近了1200,现在剩余+”+temp);}elseThread.yield();}}
}
}Test.javapublic class Test {public static void main(String args[]){BankCard bc = new BankCard();Father ft = new Father(bc);Mother mt = new Mother(bc);GrandFather gft = new GrandFather(bc);Thread thread = new Thread(ft);thread.start();Thread thread1 = new Thread(mt);thread1.start();Thread thread2= new Thread(gft);thread2.start();}}那么这个程序的意思就是父亲,母亲,祖父,都可以向银行卡里存钱,如果超过了5000就不能再存
那么我们看结果
问题出现了,父亲最后存完钱钱已经超出5000了,虚拟主机,为6000元,为什么爷爷和母亲都还能存呢?
为了解决这个问题,我们在run方法下的第一个temp = bc.getNum();语句前后分别加上
System.out.println(“看看祖父怎么回事”);temp = bc.getNum();
System.out.println(“看看祖父怎么回事”+temp);三个文件分别换成对应名字
再看结果,因为多线程每次运行结果不同,我们以接下来的结果说明
程序刚开始执行,三个线程执行run方法,然后系统将执行权交给父亲线程
然后父亲执行三次循环,香港服务器租用,系统将执行权交给祖父线程,祖父线程执行到System.out.println(“看看祖父怎么回事”+temp);这一句时将执行权交给母亲线程,母亲线程同样执行一次循环,存入1200,现在卡上有5700,按道理来讲剩下的人不能再存了,但如图所示,爷爷和父亲又都各自存了一次,美国服务器,为什么呢?
因为在父亲交换执行权的时候父亲线程的temp值已经变为4500
然后祖父交换执行权的时候祖父线程的temp值同样为4500
而母亲执行完后仅仅是母亲线程的temp变为4500,而另外两个线程的temp值还都为4500
所以他们2个各自都还能再循环一次,故出现了这种情况
那么解决办法就是将run方法下的第一个temp = bc.getNum();语句放进synchronized 之中,if循环体之外,保证当前线程获得同步监视器锁定时再重新读取金钱数目,或者if(temp <= 5000)条件变为bc.getNum()<=5000,就避免了这种看似同步实际不同步的问题
本文出自 “学海无涯” 博客,请务必保留此出处
不要惧怕黑暗,人间没有永恒的夜晚;不要担心严寒,