并发编程核心——七、脏读

对于对象的同步和异步的方法,我们在设计自己的程序的时候,一定要考虑问题的整 体,不然就会出现数据不一致的错误,很经典的错误就是脏读( dirtyread)示例代码如 下:

package com.bjsxt.chapter07;

import java.util.concurrent.TimeUnit;

public class DirtyRead {
    private String username = "bjsxt";
    private String password = "123";

    public synchronized void setValue(String username,String password){
        this.username = username;
        try{
            TimeUnit.SECONDS.sleep(2);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        this.password = password;
        System.out.println("set username : "+username+" password : "+password);
    }
    public void getValue(){
        System.out.println("get username : "+username+" password : "+password);
    }

    public static void main(String[] args)throws InterruptedException {
        DirtyRead dr = new DirtyRead();
        new Thread(){
            @Override
            public void run() {
                dr.setValue("zs","456");
            }
        }.start();
        TimeUnit.SECONDS.sleep(1);
        dr.getValue();// 不需要锁就能执行方法,会读写了一半的数据
    }
}

运行结果
并发编程核心——七、脏读
与预期不一样,想要的是 zs 456
出现这种结果是因为 get方法没加锁,导致线程2访问到了线程1未put完全的一半的数据,。

修改代码

package com.bjsxt.chapter07;

import java.util.concurrent.TimeUnit;

public class DirtyRead02 {
    private String username = "bjsxt";
    private String password = "123";

    public synchronized void setValue(String username,String password){
        this.username = username;
        try{
            TimeUnit.MINUTES.sleep(1);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        this.password = password;
        System.out.println("set username : "+username+" password : "+password);
    }
    public synchronized void getValue(){// 加了锁,只有线程执行完所有的put,才会释放锁,才会让main执行读取操作
        System.out.println("get username : "+username+" password : "+password);
    }

    public static void main(String[] args)throws InterruptedException {
        DirtyRead02 dr = new DirtyRead02();
        new Thread(){
            @Override
            public void run() {
                dr.setValue("zs","456");
            }
        }.start();
        TimeUnit.SECONDS.sleep(30);
        dr.getValue();
    }
}

运行结果
并发编程核心——七、脏读

示例总结:
在我们对一个对象的方法加锁的时候,需要考虑业务的整体性,即为 setValue/getValue 方法同时加锁 synchronized 同步关键字,保证业务(service)的 原子性,不然会出现业务错误(也从侧面保证业务的一致性)。

上一篇:PHPStorm使用PHP7新特性出现红色波浪错误


下一篇:python+selenium————元素的八大定位方法