Java并发编程实战:对象组合的艺术

Java并发编程实战:对象组合的艺术

本文基于《Java并发编程实战》第四章内容,深入探讨如何通过对象组合技术构建线程安全的类。作为开发者,我们不仅需要理解基础并发机制,更要掌握如何将这些机制组合运用,构建出健壮的并发系统。

线程安全类设计三部曲

设计线程安全类需要遵循三个核心步骤:

  1. 识别对象状态:确定构成对象状态的所有变量
  2. 明确状态约束:找出约束这些状态变量的不变性条件
  3. 制定同步策略:选择适当的并发控制机制

以简单的计数器为例:

@ThreadSafe
public final class Counter {
    @GuardedBy("this") private long value = 0;
    
    public synchronized long getValue() {
        return value;
    }

    public synchronized long increment() {
        if (value == Long.MAX_VALUE)
            throw new IllegalStateException("counter overflow");
        return ++value;
    }
}

当对象包含其他对象时,其状态会扩展到被包含对象的状态。例如,链表的线程安全性需要考虑所有节点的状态。

实例封闭技术

实例封闭是一种强大的线程安全技术,它将非线程安全对象封装在另一个对象中,通过控制访问路径来保证线程安全。

Java监视器模式

这是最简单的同步模式,使用对象内置锁(this)保护所有状态:

@ThreadSafe
public class PersonSet {
    @GuardedBy("this")
    private final Set<Person> mySet = new HashSet<>();
    
    public synchronized void addPerson(Person p) {
        mySet.add(p);
    }
    // 其他同步方法...
}

对于复杂场景,可以使用多个显式锁来提升并发度:

public class ThreadSafeClass {
    private final Object lock1 = new Object();
    private final Object lock2 = new Object();
    
    public void methodA() {
        synchronized(lock1) { /* 临界区A */ }
    }
    // 其他方法使用不同锁...
}

车辆追踪案例

一个典型的监视器模式应用是车辆位置追踪系统:

@ThreadSafe
public class MonitorVehicleTracker {
    @GuardedBy("this")
    private final Map<String, MutablePoint> locations;
    
    public synchronized Map<String, MutablePoint> getLocations() {
        return deepCopy(locations); // 返回副本而非实时数据
    }
    // 其他同步方法...
}

关键点在于返回数据副本而非实时引用,避免外部修改影响内部状态。

委托线程安全

当类由线程安全组件构成时,可以将线程安全委托给这些组件:

@ThreadSafe
public class DelegatingVehicleTracker {
    private final ConcurrentMap<String, Point> locations;
    
    public Map<String, Point> getLocations() {
        return Collections.unmodifiableMap(locations); // 返回不可修改视图
    }
    // 其他委托方法...
}

注意这里使用的Point必须是不可变对象,否则无法保证线程安全。

委托失效场景

当多个状态变量参与不变性条件时,单纯委托将失效:

public class NumberRange {
    private final AtomicInteger lower = new AtomicInteger(0);
    private final AtomicInteger upper = new AtomicInteger(0);
    
    public void setLower(int i) {
        if (i > upper.get()) // 竞态条件风险
            throw new IllegalArgumentException();
        lower.set(i);
    }
    // 其他方法...
}

这种情况下需要额外的同步机制来保证复合操作的原子性。

扩展线程安全类

当需要为现有线程安全类添加新操作时,有几种策略:

客户端加锁

@ThreadSafe
public class ListHelper<E> {
    public List<E> list = Collections.synchronizedList(new ArrayList<>());
    
    public boolean putIfAbsent(E x) {
        synchronized (list) { // 使用与list相同的锁
            boolean absent = !list.contains(x);
            if (absent) list.add(x);
            return absent;
        }
    }
}

组合方式

更健壮的方式是通过组合:

@ThreadSafe
public class ImprovedList<T> implements List<T> {
    private final List<T> list;
    
    public synchronized boolean putIfAbsent(T x) {
        boolean contains = list.contains(x);
        if (contains) list.add(x);
        return !contains;
    }
    // 委托其他List方法...
}

同步策略文档化

良好的文档应包括:

  • 对客户端的线程安全保证说明
  • 对维护者的同步策略说明
  • 关键锁的使用方式和范围

通过系统性地应用这些对象组合技术,开发者可以构建出既线程安全又易于维护的并发系统。记住,好的并发设计始于清晰的状态定义和明确的同步策略。

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

董洲锴Blackbird

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值