从头认识多线程-2.4 脏读(DirtyRead)

这一章节我们来讨论一下脏读(DirtyRead)。

1.为什么出现脏读?

因为代码没有做同步,虽然set方法同步,但是由于get方法一般都会忘了,导致读的值是被写过的


2.代码清单

(1)由于程序没有同步,并且执行太快,导致脏读

package com.ray.deepintothread.ch02.topic_4;

public class DirtyRead {
	public static void main(String[] args) throws InterruptedException {
		MyTestObjectOne myTestObjectOne = new MyTestObjectOne();
		ThreadOne threadTwo = new ThreadOne(myTestObjectOne);
		Thread thread = new Thread(threadTwo);
		thread.start();
		System.out.println("id:" + myTestObjectOne.getId() + " name:" + myTestObjectOne.getName());
	}
}

class ThreadOne implements Runnable {

	private MyTestObjectOne myTestObjectOne;

	public ThreadOne(MyTestObjectOne myTestObjectOne) {
		this.myTestObjectOne = myTestObjectOne;
	}

	@Override
	public void run() {
		myTestObjectOne.setId(1);
		myTestObjectOne.setName("ray");
	}
}

class MyTestObjectOne {
	private int id = 0;
	private String name = "init";

	public int getId() {
		return id;
	}

	public synchronized void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public synchronized void setName(String name) {
		this.name = name;
	}
}



输出:

id:0 name:init


由于没有做同步,因此在set的线程启动时,已经get了初始化的值出来


(2)由于没有做同步,代码的执行先后顺序和执行时间无法控制,导致读取的值是已经修改过的

package com.ray.deepintothread.ch02.topic_4;

public class DirtyRead2 {
	public static void main(String[] args) throws InterruptedException {
		MyTestObjectTwo myTestObjectTwo = new MyTestObjectTwo();
		ThreadTwo threadTwo = new ThreadTwo(myTestObjectTwo);
		Thread thread = new Thread(threadTwo);
		thread.start();
		Thread.sleep(100);// 是否出现脏读,这里程序的执行时间,跟下面的执行时间有密切关系
		System.out.println("id:" + myTestObjectTwo.getId() + " name:" + myTestObjectTwo.getName());
	}
}

class ThreadTwo implements Runnable {

	private MyTestObjectTwo myTestObjectTwo;

	public ThreadTwo(MyTestObjectTwo myTestObjectTwo) {
		this.myTestObjectTwo = myTestObjectTwo;
	}

	@Override
	public void run() {
		myTestObjectTwo.setId(1);
		try {
			Thread.sleep(1000);// 代码执行时间
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		myTestObjectTwo.setName("ray");
	}
}

class MyTestObjectTwo {
	private int id = 0;
	private String name = "init";

	public int getId() {
		return id;
	}

	public synchronized void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public synchronized void setName(String name) {
		this.name = name;
	}
}

输出:

id:1 name:init

从输出很明显的可以看到,id已经被修改了,但是还没有修改name的时候,就已经开始读取了。


3.解决方案-同步,而且是有技巧的同步

package com.ray.deepintothread.ch02.topic_4;

public class DirtyRead3 {
	public static void main(String[] args) throws InterruptedException {
		MyTestObjectThree myTestObjectThree = new MyTestObjectThree();
		ThreadThree threadThree = new ThreadThree(myTestObjectThree);
		Thread thread = new Thread(threadThree);
		thread.start();
		ThreadFour threadFour = new ThreadFour(myTestObjectThree);
		Thread thread1 = new Thread(threadFour);
		thread1.start();
	}
}

class ThreadThree implements Runnable {

	private MyTestObjectThree myTestObjectThree;

	public ThreadThree(MyTestObjectThree myTestObjectThree) {
		this.myTestObjectThree = myTestObjectThree;
	}

	@Override
	public void run() {
		myTestObjectThree.setValue(1, "ray");
	}
}

class ThreadFour implements Runnable {

	private MyTestObjectThree myTestObjectThree;

	public ThreadFour(MyTestObjectThree myTestObjectThree) {
		this.myTestObjectThree = myTestObjectThree;
	}

	@Override
	public void run() {
		myTestObjectThree.getValue();
	}
}

class MyTestObjectThree {
	private int id = 0;
	private String name = "init";

	public synchronized void setValue(int id, String name) {
		this.id = id;
		this.name = name;
	}

	public synchronized void getValue() {
		System.out.println("id:" + id + " name:" + name);
	}
}



输出:

id:1 name:ray


同步的确能够解决上面的问题,但是有一点需要注意的是,上面的set方法,是把两个属性一起设置的,如果分开了,就不行的,同理,get的方法同时得到两者,分开的那种不行。


总结:这一章节我们讨论了脏读的形成与解决方案。


这一章节就到这里,谢谢

------------------------------------------------------------------------------------

我的github:https://github.com/raylee2015/DeepIntoThread


目录:http://blog.csdn.net/raylee2007/article/details/51204573





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值