码迷,mamicode.com
首页 > 编程语言 > 详细

从头认识多线程-2.14 解决由同步的synchronized (newobject()) 引起的脏读的方法

时间:2016-05-12 22:57:32      阅读:247      评论:0      收藏:0      [点我收藏+]

标签:

这一章节我们来讨论一下解决由同步的synchronized (newobject()) 引起的脏读的方法。

1.造成上面脏读的原因:多线程多方法同时访问并修改某个属性域


2.解决思路

顺着上面的原因,笔者提出两种不是方法的方法

(1)只能单线程单方法访问并修改某个属性域这样就保证了执行的顺序(也就是需要同步所有访问并修改的步骤)(缺点:性能低下,优点:数据的强一致性)

(2)在多线程多方法的情况下,只能够访问多个属性域,不能够同时访问并修改某一个单一的属性域(根本目的就是分开运算,但是,在生产环境中,的确很难把一个属性域分成2个来运算,所以,笔者更趋向于第一种方法)


3.代码清单

(1)第一个思路

package com.ray.deepintothread.ch02.topic_15;

/**
 * 
 * @author RayLee
 *
 */
public class SolutionOfDirtyRead {
	public static void main(String[] args) throws InterruptedException {
		MyService2 myService = new MyService2();
		ThreadThree threadThree = new ThreadThree(myService);
		Thread thread = new Thread(threadThree);
		thread.start();
		ThreadFour threadFour = new ThreadFour(myService);
		Thread thread2 = new Thread(threadFour);
		thread2.start();
	}
}

class ThreadThree implements Runnable {

	private MyService2 myService;

	public ThreadThree(MyService2 myService) {
		this.myService = myService;
	}

	@Override
	public void run() {
		try {
			myService.update();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

class ThreadFour implements Runnable {

	private MyService2 myService;

	public ThreadFour(MyService2 myService) {
		this.myService = myService;
	}

	@Override
	public void run() {
		try {
			myService.update();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

class MyService2 {

	private Integer id = 0;

	public void updateA() throws InterruptedException {
		synchronized (id) {
			for (int i = 0; i < 5; i++) {
				System.out.println(Thread.currentThread().getName() + " " + id++);
				Thread.sleep(50);
			}
		}
	}

	public void updateB() throws InterruptedException {
		synchronized (id) {
			for (int i = 0; i < 5; i++) {
				System.out.println(Thread.currentThread().getName() + " " + id++);
				Thread.sleep(100);
			}
		}
	}

	public synchronized void update() throws InterruptedException {
		updateA();
		updateB();
	}

}

输出:

Thread-0 0
Thread-0 1
Thread-0 2
Thread-0 3
Thread-0 4
Thread-0 5
Thread-0 6
Thread-0 7
Thread-0 8
Thread-0 9
Thread-1 10
Thread-1 11
Thread-1 12
Thread-1 13
Thread-1 14
Thread-1 15
Thread-1 16
Thread-1 17
Thread-1 18
Thread-1 19


我们把updateA和updateB组合成为一个方法, 然后做方法级的同步,或者将两个方法组合成方法块的同步,这样,输出的结果就可以是同步的,不会出现脏读


(2)第二种思路

package com.ray.deepintothread.ch02.topic_15;

/**
 * 
 * @author RayLee
 *
 */
public class SolutionOfDirtyRead2 {
	public static void main(String[] args) throws InterruptedException {
		MyService myService = new MyService();
		ThreadOne threadOne = new ThreadOne(myService);
		Thread thread = new Thread(threadOne);
		thread.start();
		ThreadTwo threadTwo = new ThreadTwo(myService);
		Thread thread2 = new Thread(threadTwo);
		thread2.start();
	}
}

class ThreadOne implements Runnable {

	private MyService myService;

	public ThreadOne(MyService myService) {
		this.myService = myService;
	}

	@Override
	public void run() {
		try {
			myService.updateA();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

class ThreadTwo implements Runnable {

	private MyService myService;

	public ThreadTwo(MyService myService) {
		this.myService = myService;
	}

	@Override
	public void run() {
		try {
			myService.updateB();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

class MyService {

	private Integer id1 = 0;

	private Integer id2 = 0;

	public void updateA() throws InterruptedException {
		synchronized (this) {
			for (int i = 0; i < 5; i++) {
				System.out.println(Thread.currentThread().getName() + " id1:" + id1++);
				Thread.sleep(50);
			}
		}
	}

	public void updateB() throws InterruptedException {
		synchronized (this) {
			for (int i = 0; i < 5; i++) {
				System.out.println(Thread.currentThread().getName() + " id2:" + id2++);
				Thread.sleep(100);
			}
		}
	}

}

输出:

Thread-0 id1:0
Thread-0 id1:1
Thread-0 id1:2
Thread-0 id1:3
Thread-0 id1:4
Thread-1 id2:0
Thread-1 id2:1
Thread-1 id2:2
Thread-1 id2:3
Thread-1 id2:4


虽然输出的结果是同步的,但是也是上面所说的,一个属性域(一般是某个数的运算或者某种状态的运算)是很难分开来的。当然,如果可以分开来,这是最优解,因为既保证了同步,也保证了数据的强一致性。


总结:这一章节主要讨论了解决由同步的synchronized (newobject()) 引起的脏读的方法。


这一章节就到这里,谢谢

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

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


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


从头认识多线程-2.14 解决由同步的synchronized (newobject()) 引起的脏读的方法

标签:

原文地址:http://blog.csdn.net/raylee2007/article/details/51340392

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!