线程脏读解析

为实现多个线程调用同一个方法时,为了避免数据出现交叉问题的情况。使用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。如下图



发布了42 篇原创文章 · 获赞 32 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/m0_37027631/article/details/76603583