java 对象 线程安全_JAVA并发编程学习:构造线程安全的对象

设计线程安全的类

实例限制

当一个对象被另一个对象封装时,所有访问被被封装对象的代码路径就是全部可知的,这相比于让对象可被整个系统访问来说,更容易对代码路径进行分析。将数据封装在对象内部,把对数据的访问限制在对象的方法上,更易确保线程在访问数据时总能获得正确的锁

被限制对象一定不能溢出到它的期望可用的范围之外。可以把对象限制在本地变量、类的实例(比如私有类的成员)或线程(比如对象在线程内部从一个方法传递到另一个方法,不过前提是该对象不被跨线程共享),下面的例子未对Person的线程安全性作任何假设,但如果它是可变的,那么可能还需要额外同步

@ThreadSage

public class PersonSet

{

@GuardedBy("this")

private final Set mySet=new HashSet();

public synchronized void addPerson(Person p)

{

mySet.add(p);

}

public synchronized boolean containsPerson(Person p)

{

return mySet.contains(p);

}

}

监视器

使用私有锁对象,而不是对象的内部锁(或任何其他可公共访问的锁)

public class PrivateLock

{

private final Object myLock=new Object();

@GuardedBy("myLock") Widget widget;

void somenMethod()

{

synchronized(myLock)

{

//访问或修改widget的状态

}

}

}

范例:机动车追踪器

package com.henrysun.javaSE.bfbc;

import java.util.Collections;

import java.util.HashMap;

import java.util.Map;

import org.apache.http.annotation.GuardedBy;

/**

* 线程安全类,JAVA监视器模式

* 范例:机动车追踪器

* 一个用于调度出租车,警车,货运卡车等机动车的“机动车追踪器”,每一辆机动车都有一个String标识

* 并有一个与之对应的位置(X,Y),视图线程和多个更新线程会并发的访问数据模型

* @author Sam Flynn

*

*/

public class MonitorVehicleTracker {

@GuardedBy("this")

private final Map locations;

public MonitorVehicleTracker(Map locations)

{

this.locations=deepCopy(locations);

}

public synchronized Map getLocations() {

return deepCopy(locations);

}

public synchronized MutablePoint getLocation(String id) {

MutablePoint loc=locations.get(id);

return loc==null?null:new MutablePoint(loc);

}

public synchronized void setLocation(String id,int x,int y)

{

MutablePoint loc=locations.get(id);

if(loc==null)

{

throw new IllegalArgumentException("No such ID:"+id);

}

loc.x=x;

loc.y=y;

}

private static Map deepCopy(Map m)

{

Map result=new HashMap();

for(String id:m.keySet())

{

result.put(id, new MutablePoint(m.get(id)));

}

return Collections.unmodifiableMap(result);

}

}

/**

* 可变point

* @author Sam Flynn

*

*/

class MutablePoint

{

public int x,y;

public MutablePoint(){x=0;y=0;}

public MutablePoint(MutablePoint p)

{

this.x=p.x;

this.y=p.y;

}

}

先复制可变的数据,再返回给用户,这种实现方式只能简单的维护线程安全。如果locations集合不是非常大的话,这种做法通常不会造成性能问题。每次调用getLocations前先复制全部数据还会产生另一种副作用-即使真实的location已经改变,返回的容器的内容仍然不会改变

委托线程安全

我们向一个无状态的类(假设A)中添加一个线程安全的类型(假设B)的属性,所得组合对象仍然是线程安全的,因为A的状态就是线程安全类B的状态,并且A没有对B的状态增加额外的有效性的约束,可以说A将它的线程安全性委托给了B

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值