欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

多线程的同步问题

程序员文章站 2022-05-02 12:05:36
...

看一个例子,背景是,银行卡里有1000块钱,在柜台取800块钱,在提款机取800块钱,理论上来说,这个是不允许的

看看实现代码


package test;

public class FetchMoney {

    public static void main(String[] args) {

        Bank bank = new Bank();

        MoneyThread thread1 = new MoneyThread(bank); // 柜台手续线程
        MoneyThread thread2 = new MoneyThread(bank); // 自助机手续线程

        thread1.start();
        thread2.start();
    }

}

class Bank {
    private int money = 1000;

    public int getMoney(int money) {

        if(money < 0) {
            return -1;
        }

        if(money > this.money) {
            return -2;
        }

        try {
            Thread.sleep(1000); // 取钱前的一些准备工作
        } catch (Exception e) {
            e.printStackTrace();
        }

        this.money -= money;
        return money;
    }
}

class MoneyThread extends Thread {

    private Bank bank;

    public MoneyThread(Bank bank) {
        this.bank = bank;
    }

    @Override
    public void run() {
        System.out.println(bank.getMoney(800));
    }
}


执行的结果是

800
800

Process finished with exit code 0

1000块钱的余额居然真的取出2次800块钱了

问题的根源在于,2个线程会同时访问一个实例的某个成员变量,2条线程判断条件时成员变量的值均可能是还没取钱时候的值

要解决这个问题,我们可以这么想,取钱的时候(即调getMoney方法的时候),只允许1条线程访问,就解决了

代码如下:


package test;

public class FetchMoney {

    public static void main(String[] args) {

        Bank bank = new Bank();

        MoneyThread thread1 = new MoneyThread(bank); // 柜台手续线程
        MoneyThread thread2 = new MoneyThread(bank); // 自助机手续线程

        thread1.start();
        thread2.start();


    }

}

class Bank {
    private int money = 1000;

    public synchronized int getMoney(int money) {

        if(money < 0) {
            return -1;
        }

        if(money > this.money) {
            return -2;
        }

        try {
            Thread.sleep(1000); // 取钱前的一些准备工作
        } catch (Exception e) {
            e.printStackTrace();
        }

        this.money -= money;
        return money;
    }

    public int getMoney2(int money) {

        synchronized(this) {
            if (money < 0) {
                return -1;
            }

            if (money > this.money) {
                return -2;
            }

            try {
                Thread.sleep(1000); // 取钱前的一些准备工作
            } catch (Exception e) {
                e.printStackTrace();
            }

            this.money -= money;
        }
        return money;
    }
}

class MoneyThread extends Thread {

    private Bank bank;

    public MoneyThread(Bank bank) {
        this.bank = bank;
    }

    @Override
    public void run() {
        System.out.println(bank.getMoney(800));
    }
}


调用getMoney或者getMoney2都可以


结果为:

800
-2

Process finished with exit code 0