线程---脏读

示例代码:

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 synchronized void getValue() {
        System.out.println("getValue方法得到:username=" + this.username + ",password=" + this.password);
    }

    public synchronized static void main(String[] args) throws Exception {
        final DirtyRead dr = new DirtyRead();
        Thread t1 = new Thread(new Runnable() {

            @Override
            public void run() {
                dr.setValue("z3", "456");

            }
        });
        t1.start();
        Thread.sleep(1000);
        dr.getValue();
    }
}

运行结果:


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

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

如果不加synchronized关键字程序就会出现以下结果(脏读):


描述:A在9:00的时候向数据库发送了一条select语句,预计9:10查到这条数据,B在9:05的时候向数据库发送了update语句,那么A读到的数据是原来的100还是B修改后的200呢?答案是100.


这就体现了oracle数据库的一致性读,在9:00的时候发起的select语句,那么我们查到的数据就是9:00时候的数据。oracle数据库中有undo这个概念,好比一个日志,在执行dml操作是,都会把老值放在undo里,然后再进行修改。undo就是防止DML操作失败,在操作错误的时候可以进行回滚就是要回滚的时候就是将undo里面的数据回滚回来。这个例子就是其实去undo里面进行的查找数据,宁可跑出一个异常(snapshot to old)也不会将新值返回.


扫描二维码关注公众号,回复: 3022091 查看本文章



猜你喜欢

转载自blog.csdn.net/weixin_41933719/article/details/80944177