一.限制设计——从结构上说,是利用封装技术,保证某一时刻只有一个活动访问某个对象。
方式主要三类,方法限制、线程限制和对象内限制
方法限制:
1.方法内部限制:采用局部变量方式
2.方法间传递限制:
a.调用者copy:比如print(p) 可以改为print(new Point(p));
b.接收者copy:Point p=new Point(p.x,p.y);
c.标量参数:print(int x,int y);d.print(p.x,p.y);
线程限制:
1.最简单的方法是将所有可变对象都放在一个线程内执行
public display(){
new Thread(){
public void run(){//do something here}
}.start()
}
2.线程私有成员变量
最直接的办法是利用现有类:ThreadLocal.
当然你可以利用Thread.currentThread()自己实现一个类似功能的类,但Thread.currentThread有限制,就是对特定线程的一类。
而ThreadLocal则摆脱了这样的限制。而且在线程内对ThreadLocal私有变量的读写不需要同步。
对象限制:
在前面两种方法都不能做到对对象的限制访问时,你就不得不使用锁。但同时,也可以对对象内部及不同部分的访问进行结构上的限制。
1.适配器模式
比如 class Point{
public double x;
public double y;
public synchronized double getX(){};
//……
}
采用对象限制的设计方式,会将synchronized 锁移除到一个其他对象里,这样就解脱了Point.
like this
class SychPoint {
private final Point point=new Point();
public synchronized double getX(){point.x}
}
class Point{
public double x;
public double y;
public double getX(){};
}
说白了就是采用适配器模式,改变了一下原来类的结构。java.util.Collection framework 里面就是使用这种策略组织起集合类的同步。
2.子类化
将锁延迟到子类实现,这里将不再罗嗦。
二.同步设计
使用锁的注意事项
1.有些入口锁在只有少数线程访问的情况下,可以很好的工作,开销并不大。但是当并发量变大,竞争加剧,开销也变大,系统的性能会随之下降。大多数线程会把大部分时间浪费在等待上。系统出现了延迟,限制了并发系统的优越性。
2.使用太多的锁,会增加系统负担,以及不可料的情况发生,比如死锁。
3.只用一把锁来保护一个功能的多个方面会导致资源竞争。
4.长时间持有锁,会带来性能问题和异常处理的复杂。
5.有时候加锁并不一定能保证得到我们想要的结果。
对付以上这些问题,没有什么最佳策略,大都需要去权衡各个方面的利弊来进行设计。写多线程的程序,前期的设计比后期维护更为重要。
初期的设计原则,
1.减少同步
a.用户可以接受陈旧数据,可以拿掉同步,使用volatile
b.用户在得到非法数据时,只要能得到提示就够了,可以使用double-check方法。
在不同步时check一次,再在同步状态在check一次。这么做的意义在于缩小锁使用范围,在第一次check不满足的情况,跳出方法,那么锁也就用不到了。
c.只对维护状态部分加锁:当对象的某个同步方法是比较耗时的操作,那么锁持有的时间就越长,而仅仅是为了保持一个状态是,可以采用openCall的方式,减少持有锁时间。
public sychronized void updateState(){}
public void readFile(){
updateState();//持有锁
file.read();
}
如上,这种方式的前提是程序不需要同步一个方法中无状态的部分。如果整个方法都需要锁,那这种方式就不适用了.
D.能使用同步块,就不需同步整个方法。
2.分解同步:
分解类
将锁拆分到辅助类中
分解锁
如果不愿分解类,可以设计分解锁
private static Object lock1 = new Object();
private static Object lock2 = new Object();
synchronize(lock1){}
synchronized(lock2){}
在jdk 5.0之后的并发包里,已有可重入锁供使用。
隔离成员变量
Person的age,income等属性都需要同步处理,以保证并发修改时,可以设计一些同步的int,Double等类型(util.concurrent已提供类似的类),将锁交给辅助类去处理。起到隔离作用.