为实现多个线程调用同一个方法时,为了避免数据出现交叉问题的情况。使用synchronized关键字来进行同步。虽然在赋值时进行了同步,但在取值时有可能出现一些意想不到的意外,这种情况就是脏读。发生脏读的情况是在读取实例变量时,此值已经被其他线程修改过了。
一下编写相关测试类。
PublicVar.java
public class PublicVar {
public String username = "A";
public String password = "AA";
synchronized public void setValue(String username, String password) {
try {
this.username = username;
Thread.sleep(5000);
this.password = password;
System.out.println("setValue method thread name=" + Thread.currentThread().getName() +
"username="+username+"password="+password);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void getValue(){
System.out.println("getValue method thread name=" +Thread.currentThread().getName()+
"usernme="+username+"password="+password);
}
}
注意其中的setValue()方法添加了关键字synchronized,而getValue()方法没有添加
创建线程类并调用PublicVar类中的setValue方法。
ThreadA.java
public class ThreadA extends Thread{
private PublicVar publicVar;
public ThreadA(PublicVar publicVar) {
super();
this.publicVar=publicVar;
}
@Override
public void run() {
super.run();
publicVar.setValue("B", "BB");
}
}
测试类
public class Test {
public static void main(String[] args) {
try {
PublicVar publicVar = new PublicVar();
ThreadA threadA = new ThreadA(publicVar);
threadA.start();
/*
* 在PublicVar类的setValue()方法中给username赋值后让线程睡了5秒之后才给password赋值
* this.username = username;
* Thread.sleep(5000);
* this.password = password;如果在线程睡的这5秒中之内有其他线程访问这两个变量,就会得到username=B,password=AA
* 此时让线程睡0.2秒然后执行getValue()方法,这个时候 0.2秒小于5秒。因此得到的值就是username=B,password=AA。如果此时让
* 线程睡的时间大于5秒则username=B,password=BB。这就是所谓的脏读
*/
Thread.sleep(200);
//Thread.sleep(10000);
publicVar.getValue();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
仔细看注释。
控制台打印结果:
避免出现脏读的方法就是在相应的方法前面添加关键字synchronized。如下图