天天看点

一把锁引发的问题,synchronized方法与非synchronized方法共存产生数据脏读问题

模拟场景:

写一段小程序,一个方法给某人账户充值,另一个方法查询某人的账户,如果两个方法都不加锁,并发情况下肯定会问题,现在只给充值方法加锁,查询方法不加,由于synchronized与非synchronized方法可以同时运行,所以查询方法可能产生脏读问题。

public class Account {


    String name;
    double balance;

    public synchronized void setBalance(String name, double balance) {
        this.name = name;

        try {
            Thread.sleep(2000);
        } catch (InterruptedException exception) {
            exception.printStackTrace();
        }

        this.balance = balance;


    }

    public double getBalance(String name) {
        if (name.equals(this.name)) {
            return this.balance;
        }
        return 0.0;
    }

    public static void main(String[] args) throws InterruptedException {
        Account acc = new Account();
        new Thread(() -> acc.setBalance("张三", 100)).start();

        TimeUnit.SECONDS.sleep(1);//暂停1秒

        /**
         * setBalance还未执行完成,读到的还是balance的默认值,即0.0,也就是脏读
         */
        System.out.println(acc.getBalance("张三"));

        TimeUnit.SECONDS.sleep(2);//再暂停3秒

        /**
         * setBalance已执行完成,读到的是balance的最新值,即100.0
         */
        System.out.println(acc.getBalance("张三"));

    }

}      

结果

0.0

100.0

 是否需要给读方法同时加上synchronized?看需求,如果需求场景允许出现脏读(仅仅是读,不进行任何写操作),可以不用加,加上synchronized性能将急剧下降,如果场景不允许脏读,该加还是要加。

public synchronized double getBalance(String name) {
        if (name.equals(this.name)) {
            return this.balance;
        }
        return 0.0;
    }      
public double getBalance(String name) {
        synchronized (this) {
            if (name.equals(this.name)) {
                return this.balance;
            }
            return 0.0;
        }
    }      
public static synchronized void fun(){
        // to do something
    }

 //等价于
 public static  void fun(){

       synchronized(Account.class){
            // to do something
       }
   }