在之前,我们都知道通过synchoronized关键字来实现对方法的同步。
在线程操作实例变量的情况下,虽然在赋值时进行了同步,但在取值时有可能出现一些意想不到的意外,这种情况就是脏读。发生脏读的情况是在读取实例变量时,此值已经被其他线程更改过。
package com.example.test;
public class Account {
private String username="a";
private String userpassword = "aa";
synchronized public void setValue(String username,String userpassword) {
this.username = username;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.userpassword = userpassword;
}
public String getValue() {
return username+" "+userpassword;
}
}
public class Test169 {
public static void main(String[] args) {
Account t = new Account();
MyThreadfirst mf = new MyThreadfirst(t, "laoqiang", "123");
Thread t1 = new Thread(mf);
t1.start();
System.out.println(t.getValue());
}
}
class MyThreadfirst implements Runnable{
private Account a;
private String username;
private String password;
public MyThreadfirst(Account a, String username, String password) {
super();
this.a = a;
this.username = username;
this.password = password;
}
@Override
public void run() {
// TODO Auto-generated method stub
a.setValue(username,password);
}
}
首先我们知道synchronized 关键字是锁住的是对象锁,在本例中,我们创建了一个对象,所以线程执行要获取对象锁,但是我们看到getVlaue方法没有用synchronized 修饰,而setValue方法用了synchronized 修饰。所以执行setValue方法会同步,但是getValue方法可以异步。在读取的时候造成脏读的环境。
总结:摘自书上,自己稍微修改。
当一个线程调用对象加入synchronized 关键宇的x 方法时,A线程就获得了x方法锁,更准确地讲,是获得了对象的锁,所以其他线程必须等A 线程执行完毕才可以调用X 方法,但B 线程可以随意调用其他的非synchronized 同步方法。
当一个 线程调用对象加入synchronized 关键字的X 方法时,A 线程就获得了x方法所在对象的锁,所以其他线程必须等A线程执行完毕才可以调用x 方法,而另外线程如果调用声明了synchronized关键字的非X方法时,必须等A线程将X方法执行完,也就是释放对象锁后才可以调用。这时A线程已经执行了一个完整的任务。