从头认识多线程-2.16 证明使用整数属性域作为多线程监视器是不同步的

这一章节接着上一章节最后的错误的思路,我们来证明使用整数属性域作为多线程监视器是不同步的。

1.用同一个属性域作为多线程监视器,是不同步的

package com.ray.deepintothread.ch02.topic_16;

/**
 * 
 * @author RayLee
 *
 */
public class DirtyReadWithSynchBlock {
	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.updateA();
		} 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.updateB();
		} 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);
			}
		}
	}

}

输出:

Thread-0 0
Thread-1 1
Thread-0 2
Thread-1 3
Thread-0 3
Thread-0 4
Thread-0 5
Thread-1 5
Thread-1 6
Thread-1 7


从上面的输出可以得出相应结论


另一个例子:

package com.ray.deepintothread.ch02.topic_16;

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

class ThreadThree implements Runnable {

	private MyService2 myService;

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

	@Override
	public void run() {
		try {
			myService.updateA();
		} 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.updateB();
		} 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("id:" + id);
				System.out.println(Thread.currentThread().getName() + " " + id++);
				Thread.sleep(50);
				System.out.println("-------------------");
			}
		}
	}

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

}

输出:

id:0
thread A 0
id:1
thread B 1
-------------------
id:2
thread A 2
-------------------
id:3
thread A 3
-------------------
id:4
thread B 4
-------------------
id:5
thread A 5
-------------------
-------------------
id:6
id:6
thread B 6
thread A 7
-------------------
-------------------
id:8
thread B 8
-------------------
id:9
thread B 9
-------------------


从输出的结果,特别看到中间的id=6的时候,threadA和threadB计算的结果,就不言而喻了。


2.伪synchronized (newobject())同步的例子

package com.ray.deepintothread.ch02.topic_16;

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

class ThreadOne implements Runnable {

	private MyService myService;

	private int id = 0;

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

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

class ThreadTwo implements Runnable {

	private MyService myService;

	private int id = 0;

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

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

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

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

}

输出:

Thread-0 1
Thread-0 2
Thread-0 3
Thread-0 4
Thread-0 5
Thread-1 1
Thread-1 2
Thread-1 3
Thread-1 4
Thread-1 5


看上去上面的结果是同步的,而且看上去,我们也是对于同一个属性域进行同步访问和修改,但是,其实不是的。

我们上面的步骤如下:

(1)赋值给每一个线程的id

(2)多线程进行访问与修改

实际上我们一直访问和修改的是线程对象里面的id,而不是在main里面的id,我们将上面的代码简化,然后大家再看看


package com.ray.deepintothread.ch02.topic_16;

/**
 * 
 * @author RayLee
 *
 */
public class SynchBlock2 {
	public static void main(String[] args) throws InterruptedException {
		MyService3 myService = new MyService3();
		ThreadFive threadFive = new ThreadFive(myService);
		Thread thread = new Thread(threadFive);
		thread.start();
		ThreadSix threadSix = new ThreadSix(myService);
		Thread thread2 = new Thread(threadSix);
		thread2.start();
	}
}

class ThreadFive implements Runnable {

	private MyService3 myService;

	private int id = 1;

	public ThreadFive(MyService3 myService) {
		this.myService = myService;
	}

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

class ThreadSix implements Runnable {

	private MyService3 myService;

	private int id = 1;

	public ThreadSix(MyService3 myService) {
		this.myService = myService;
	}

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

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

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

}

输出:

Thread-0 1
Thread-0 2
Thread-0 3
Thread-0 4
Thread-0 5
Thread-1 1
Thread-1 2
Thread-1 3
Thread-1 4
Thread-1 5


输出结果跟上面的没有区别,因此,得出结论是,方法里面修改的是每一个线程对象里面的id,是两个不同的属性域,这当然不会出现脏读的情况。


总结:这一章节我们证明了使用整数属性域作为多线程监视器是不同步的。


这一章节就到这里,谢谢

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

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


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


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值