1.4 脏读

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ksdb0468473/article/details/73199672

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

public class DirtyRead {

    private String username = "bjsxt";
    private String password = "123";

    public synchronized void setValue(String username, String password) {
        this.username = username;

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

        this.password = password;

        System.out.println("setValue最终结果;username = " + username + ",password = " + password);
    }

    public void getValue() {
        System.out.println("getValue方法得到:username = " + this.username + ",password = " + this.password);
    }

    public static void main(String[] args) {
        final DirtyRead dirtyRead = new DirtyRead();

        Thread t1 = new Thread(() -> {
            dirtyRead.setValue("z3", "456");
        });

        t1.start();

        try{
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        dirtyRead.getValue();
    }

}

上面的代码定义了类DirtyRead,其中有两个私有属性username和password,同时设置了两个方法,一个是setValue,一个是getValue,其中setValue就是设置用户名和密码的,但是在方法前加了synchronized 关键字,而getValue没有,就像上一节中说到的,在这种情况下,getValue是会和setValue同时请求的,不会产生阻塞,所以,这里的main方法中,创建了一个DirtyRead的实例,然后创建了一个新的线程,在这个线程中,我们设置了新的用户名和密码,然后在main线程中,直接获取了用户名和密码。结果如下所示:

getValue方法得到:username = z3,password = 123
setValue最终结果;username = z3,password = 456

这个结果说明,在t1线程设置用户名和密码的过程中,main线程就已经获取了用户名和密码的值了,因为getValue的时候username已经是z3了,而密码还没有变更。这就是脏读了,读取的内容并不是最终的结果,而是中的一个值,如果让getValue的结果正确,就必须让setValue之后才能使用getValue方法,那么,这里可以使用上一节中讲到的思路,由于在同一个对象中使用synchronized 关键字的不同方法,因为加锁是在对象级别的,所以当一个方法执行的时候,其他加synchronized 锁的方法也都会被阻塞住。

所以根据上面说的思路,最终做一点小小的修改:

public synchronized void getValue() {
    System.out.println("getValue方法得到:username = " + this.username + ",password = " + this.password);
}

修改之后再来看结果:

setValue最终结果;username = z3,password = 456
getValue方法得到:username = z3,password = 456

可以看到,已经没有脏读的现象了

猜你喜欢

转载自blog.csdn.net/ksdb0468473/article/details/73199672
1.4