java多线程之线程安全-构造函数捕获模式

在java并发编程实战p58页的脚注的时候没看懂,然后查百度,终于理解了,所以在这里记录一下

脚注:如果将拷贝构造函数实现为this(p.x,p.y),那么会产生竞态 条件,而私有构造函数则可以避免这种竞态条件.这是私有构造函数捕获模式的一个实例。

先上代码

public class Main {
 
	public static void main(String[] args) {
		final SafePoint originalSafePoint = new SafePoint(1, 1);
 
		new Thread(new Runnable() {
			@Override
			public void run() {
				originalSafePoint.set(2, 2);
				System.out.println("Original : " + originalSafePoint.toString());
			}
		}).start();
 
		new Thread(new Runnable() {
			@Override
			public void run() {
				SafePoint copySafePoint = new SafePoint(originalSafePoint);
				System.out.println("Copy : " + copySafePoint.toString());
			}
		}).start();
	}
 
}
 
// 线程安全类
class SafePoint {
 
	private int x, y;
 
	private SafePoint(int[] a) {
		this(a[0], a[1]);
	}
 
	public SafePoint(SafePoint p) {
		this(p.get());
	}
 
	public SafePoint(int x, int y) {
		this.x = x;
		this.y = y;
	}
 
	public synchronized int[] get() {
		return new int[] { x, y };
	}
 
	public synchronized void set(int x, int y) {
		this.x = x;
		// Simulate some resource intensive work that starts EXACTLY at this
		// point, causing a small delay
		try {
			Thread.sleep(10 * 100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.y = y;
	}
 
	@Override
	public String toString() {
		return "(" + x + "," + y + ")";
	}
}
 
// 线程不安全类
class SafePoint2 {
 
	private int x;
	private int y;
 
	public SafePoint2(int x, int y) {
		this.x = x;
		this.y = y;
	}
 
	public SafePoint2(SafePoint2 safePoint2) {
		this(safePoint2.x, safePoint2.y);
	}
 
	public synchronized int[] get() {
		return new int[] { x, y };
	}
 
	public synchronized void set(int x, int y) {
		this.x = x;
		// Simulate some resource intensive work that starts EXACTLY at this
		// point, causing a small delay
		try {
			Thread.sleep(10 * 100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.y = y;
	}
 
	@Override
	public String toString() {
		return "(" + x + "," + y + ")";
	}
}

当时没有看懂,这个竟态条件到底在哪里。现在解释一下吧

不安全

  1. 假设当第一个线程在运行originalSafePoint.set(2, 2);的是发生上下文切换,第二个线程开始执行,如果用的是(// 线程不安全类)SafePoint2
  2. 当调用了this.x = x;的时候又发生上下文切换,运行了originalSafePoint.set(2, 2);,
  3. 然后又发生上下文切换,被修改过的y又被 this.y = y;这样复制了

安全

  1. 假设当第一个线程在运行originalSafePoint.set(2, 2);的是发生上下文切换,第二个线程开始执行,如果用的是(// 线程安全类)SafePoint
  2. 会调用this(p.get());,而这时锁还被第一个运行set的线程持有会阻塞,直道set操作完成,锁才释放
  3. 这样p.get()得到了set后的正确值,就没有线程安全问题啦
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值