如何用面向对象的思想写好并发程序

防止变量的共享

在声明一个变量时候要通过方法的封装暴露对象的修改和查询操作,以此为入口来控制变量的并发,对于不变的对象尽量声明成final类型,告诉别人这个便利不会被改变。

识别共享变量的条件

防止变量之间的竞态问题,比如下面的代码:设置了上限和下限,这里有个隐含的条件上限一定要>=下限,虽然变量声明成了AtomicLong,但是在并发的时候需改时候遇到if条件可能会造成下限高于上限的问题。原因在于条件判断和修改结果不是原子操作,这是个典型的竞态问题。修改方案是set方法加synchronized

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class SafeWM {
// 库存上限
private final AtomicLong upper =
new AtomicLong(0);
// 库存下限
private final AtomicLong lower =
new AtomicLong(0);
// 设置库存上限
void setUpper(long v){
// 检查参数合法性
if (v < lower.get()) {
throw new IllegalArgumentException();
}
upper.set(v);
}
// 设置库存下限
void setLower(long v){
// 检查参数合法性
if (v > upper.get()) {
throw new IllegalArgumentException();
}
lower.set(v);
}
// 省略其他业务代码
}

制定并发访问策略

  1. 防止共享
  2. 采取不变模式。这样修改一个对象就是创建了一个新对象
  3. 利用管程和其他并发工具来

要注意几点

  1. 采用成熟的工具类避免重复开发轮子
  2. 尽量避免使用低级原语入synchronized、lock等方式,而是采用并罚保
  3. 尽量以并发安全为主,尽量避免过早优化代码