示例代码:
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();
}
}
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 查看本文章