Java并发编程:面向对象思想与并发编程思想的融合

发布时间 2023-11-27 23:54:56作者: kiper

1. 封装共享变量

1.1 识别可变化与不变的共享变量

识别可变化与不可变化的共享变量。
针对初始化后不再改变的变量,可以添加final修饰。不仅编译器编译更快,也对后续开发人员指明了变量属性,更防范了意想不到的修改行为。

1.2 针对可变化的共享变量,进行封装处理

针对共享变量的访问,若是没有统一的入口,很容易造成并发问题。正好,面向对象思想有"封装"这一概念,正好可以将共享变量作为私有属性,而开放公共方法作为访问共享变量的入口。

如针对count变量的访问。

Class Count {

  private int cnt;

  public synchronized int get() {
    return cnt;
  }

  public synchronized int add() {
    cnt++;
  }

}

2. 识别约束条件

共享变量之间的约束条件,反映在代码里基本上都会有if语句

假设一个产品有最低价与最高价,且最高价必须大于最低价。当前setLow()及setUp()方法的实现都使用了原子类进行获取值并判断,是否还存在问题?
当前setLow()及setUp()方法其实存在竞态条件。假设当前最低价1元,最高价4元,现在线程AB同时分别修改最低价为3元,最高价为2元,也是可以修改成功的。这个约束条件实际上是没有识别并拦截的。
使用了原子类只保证了low与up各自的并发安全,并没有保证最高价必须大于最低价,因为获取另外一个值并进行比较的操作并非原子操作。

Class Product {
    private final AtomicInteger low = new AtomicInteger(0);

    private final AtomicInteger up = new AtomicInteger(0);

    public void setLow(int val) {
        if (val > up.get()) {
            throw new IllegalArgumentException();
        }
        low.set(val);
    }

    public void setUp(int val) {
        if (val < low.get()) {
            throw new IllegalArgumentException();
        }
        up.set(val);
    }
}

正确的修改应该对setLow()及setUp()的代码进行加锁。

3. 制定并发访问策略

常见的并发设计思路:

  • 避免共享
  • 不变模式
  • 管程及其他同步工具