package 对象及变量的并发访问2;
/**
* 脏读
*
* 在多个线程调用同一个方法时为了避免数据出现交叉的情况,使用synchronized关键字来进行同步
* 虽然在赋值时进行了同步,但在取值时有可能出现一些意想不到的情况,这种情况就是脏读(dirty read)
* 发生脏读的原因是在读取实例变量的时候,此值已经被其他线程改变。
*
* 出现脏读是因为public void getValue()方法并不是同步的,所以可以在任意时刻调用,解决办法就是加上synchronized关键字
*
* 当线程A调用任何anyObject对象加入synchronized关键字的X方法时,A线程就获得了X方法所在的对象锁,但B线程可以随意调用其他
* 非synchronized同步方法
* 当A线程调用anyObject对象加入synchronized关键字X方法时,A线程就获得了X方法所在对象的锁,所以其他线程必须等待A线程执行
* 完后才可以调用X方法,而B线程如果调用声明了synchronized关键字的非X方法,必须等A线程将X方法执行完,也就是将对象锁进行释放
* 后才可以调用,这是A线程已经执行了一个完整的任务,也就是说usernsme和password这两个实例已经同时被赋值,不存在脏读的基本环境。
*
* 多线程执行同一个业务对象中的不同同步方法时,是按顺序同步的方式调用的。
* 脏读前一定会出现不同线程一起去写实例变量的情况,这就是不同线程“争抢”实例变量的结果。
*/
class PublicVarT216{
public String unsername="A";
public String password="AA";
synchronized public void setValue(String unsername,String password){
try {
this.unsername=unsername;
Thread.sleep(5000);
this.password=password;
System.out.println("setValue method thread name="+Thread.currentThread().getName()+
" username="+unsername+" password="+password);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized public void getValue(){
System.out.println("getValue method thread name="+Thread.currentThread().getName()+
" username="+unsername+" password="+password);
}
}
class MyThreadAT216 extends Thread{
private PublicVarT216 publicVarT216;
public MyThreadAT216(PublicVarT216 publicVarT216){
super();
this.publicVarT216=publicVarT216;
}
@Override
public void run() {
super.run();
publicVarT216.setValue("B","BB");
}
}
class RunT216{
public RunT216(){
try {
PublicVarT216 publicVarT216=new PublicVarT216();
MyThreadAT216 at216=new MyThreadAT216(publicVarT216);
at216.start();
//输出结果受睡眠时间影响
Thread.sleep(200);
publicVarT216.getValue();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class T2106 {
public static void main(String[] args) {
RunT216 runT216=new RunT216();
}
}
脏读——T2106
最新推荐文章于 2021-08-12 15:44:35 发布