Java并发编程实战 - 第4章 对象的组合

如何通过线程安全的组件组合设计线程安全的类?
首先要封装所有状态,封装简化了安全类的实现过程。
设计线程安全的类,需考虑三个基本要素

  • 找出构成对象状态的所有变量
  • 找出约束状态变量的约束条件–>不变性条件和后验条件
  • 建立对象状态的并发访问管理策略

要满足对象的状态的约束条件,就需要借助于原子性和封装性。

依赖状态的操作
如果某个操作中包含有基于状态的先验条件(Precondition),如没有则添加,那么这个操作称为依赖状态操作 。

实现等待条件为真才执行的操作的方法有:
内置机制(如等待和通知);现有的类库中的类(如BlockingQueue)。

状态的所有权
对象封装了它拥有的状态,则对象对它封装的状态拥有所有权。
如果发布一个可变对象的引用,就不在独占所有权。
容器类表现为所有权分离,容器类拥有自身的状态,而客户代码则拥有容器内各个对象的状态。

通过封闭和加锁实现线程安全的类

public class PersonSet {
    private final Set<Person> mySet = new HashSet<Person>();

    public synchronized void addPerson(Person p) {
        mySet.add(p);
    }

    public synchronized boolean containsPerson(Person p) {
        return mySet.contains(p);
    }

    interface Person {
    }
}

PersonSet类是线程安全的类,它将状态(mySet )封装起来,并对访问这个状态的方法进行加锁。
但Person类如果是可变的,需要设计成线程安全的类来安全的使用Person对象。

创建线程安全类的策略1 - Java监视器模式
Java监视器模式的对象会把对象的所有可变状态都封装起来,并有对象自己的内置锁来保护。

私有锁

public class PrivateLock {
    private final Object myLock = new Object();
    Widget widget;
    void someMethod() {
        synchronized (myLock) {
            // Access or modify the state of widget
        }
    }
}

创建线程安全类的策略2 - 线程安全性的委托
通过对象的组合,将线程安全性委托给现有的线程安全类。
如果一个类是由多个独立且线程安全的状态变量组成,并且在所有的操作中都不包含无效状态的转换,那么可以将线程安全性委托给底层的状态变量。
示例:PersonList将线程安全性委托给底层的线程安全状态变量

public class PersonList {
    private final List<Person> myList = new CopyOnWriteArrayList<Person>();//安全性委托

    public void addPerson(Person p) {
        myList.add(p);
    }

    public boolean containsPerson(Person p) {
        return myList.contains(p);
    }

    interface Person {
    }
}

线程安全性委托要考虑下列问题:
1. 状态变量要是线程安全的。
2. 多个线程安全的状态变量是独立的。
3. 多个线程安全的状态变量有不变性条件约束–不能直接委托,需要对操作加锁。
4. 类含有复合操作– 不能直接委托,需要对操作加锁。
5. 什么条件下可以发布底层的状态变量?
如果一个状态变量是线程安全的,并且没有任何不变性条件约束它的值,在变量的操作上也不存在任何不允许的状态转换,那么就可以安全地发布这个变量。

在现有的线程安全类中添加功能
1.修改原始的类
2.扩展原始类(继承)
3.扩展原始类的功能,将扩展代码放到一个“辅助类”中–通过客户端加锁。
4.组合–通过客户端加锁。

示例: 扩展原始类的功能

@NotThreadSafe
class BadListHelper <E> {
    public List<E> list = Collections.synchronizedList(new ArrayList<E>());
    public synchronized boolean putIfAbsent(E x) {//和list对象不是同一锁
        boolean absent = !list.contains(x);
        if (absent)
            list.add(x);
        return absent;
    }
}

@ThreadSafe
class GoodListHelper <E> {
    public List<E> list = Collections.synchronizedList(new ArrayList<E>());

    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;

    /**
     * PRE: list argument is thread-safe.
     */
    public ImprovedList(List<T> list) { this.list = list; }

    public synchronized boolean putIfAbsent(T x) {
        boolean contains = list.contains(x);
        if (contains)
            list.add(x);
        return !contains;
    }

    // Plain vanilla delegation for List methods.
    // Mutative methods must be synchronized to ensure atomicity of putIfAbsent.

    public int size() {
        return list.size();
    }

    public boolean isEmpty() {
        return list.isEmpty();
    }

    public boolean contains(Object o) {
        return list.contains(o);
    }

    public Iterator<T> iterator() {
        return list.iterator();
    }

    public Object[] toArray() {
        return list.toArray();
    }

    public <T> T[] toArray(T[] a) {
        return list.toArray(a);
    }

    public synchronized boolean add(T e) {
        return list.add(e);
    }

    public synchronized boolean remove(Object o) {
        return list.remove(o);
    }

    public boolean containsAll(Collection<?> c) {
        return list.containsAll(c);
    }

    public synchronized boolean addAll(Collection<? extends T> c) {
        return list.addAll(c);
    }

    public synchronized boolean addAll(int index, Collection<? extends T> c) {
        return list.addAll(index, c);
    }

    public synchronized boolean removeAll(Collection<?> c) {
        return list.removeAll(c);
    }

    public synchronized boolean retainAll(Collection<?> c) {
        return list.retainAll(c);
    }

    public boolean equals(Object o) {
        return list.equals(o);
    }

    public int hashCode() {
        return list.hashCode();
    }

    public T get(int index) {
        return list.get(index);
    }

    public T set(int index, T element) {
        return list.set(index, element);
    }

    public void add(int index, T element) {
        list.add(index, element);
    }

    public T remove(int index) {
        return list.remove(index);
    }

    public int indexOf(Object o) {
        return list.indexOf(o);
    }

    public int lastIndexOf(Object o) {
        return list.lastIndexOf(o);
    }

    public ListIterator<T> listIterator() {
        return list.listIterator();
    }

    public ListIterator<T> listIterator(int index) {
        return list.listIterator(index);
    }

    public List<T> subList(int fromIndex, int toIndex) {
        return list.subList(fromIndex, toIndex);
    }

    public synchronized void clear() { list.clear(); }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《Java并发编程实战》是一本经典的Java并发编程指南,由Brian Goetz等人撰写。这本书针对Java多线程并发编程的实践问题给出了详细的解决方案和最佳实践。 该书的主要内容包括:线程安全性、对象的共享与发布、锁的优化、性能与可伸缩性、构建和组合对象、基础构建模块、任务执行、取消与关闭、线程池的使用、显式锁、构建自定义的同步工具等。 通过阅读这本书,读者可以了解Java中的各种并发问题,并学习如何设计和实现线程安全Java应用。该书引入了很多并发编程的常见问题,例如:竞态条件、死锁、活跃性危险等,并提供了一些模式和技术来解决这些问题。 除了基础知识之外,该书还介绍了一些高级的并发编程概念,例如:并发集合、同步类、线程池等。这些内容将帮助读者更好地理解和利用Java并发编程能力。 总的来说,《Java并发编程实战》是一本权威而实用的Java并发编程指南,适合对多线程编程有一定了解的Java开发人员阅读。通过阅读这本书,读者可以更深入地理解Java并发编程的原理与应用,提高自己的并发编程能力。 ### 回答2: 《Java并发编程实战》是由美国计算机科学家布莱恩·戈策等人合著的一本书,是学习Java并发编程的经典教材。这本书系统地介绍了Java中的多线程、并发和并行编程的基本知识和应用。该书分为三个部分,分别是基础篇、高级主题篇和专题扩展篇。 在基础篇中,书中详细介绍了Java内存模型、线程安全性、对象的共享、发布和逸出等概念。同时,还对Java中的锁、线程池、阻塞队列等常用并发工具进行了深入讲解,帮助读者理解并发编程的基本原理和机制。 高级主题篇则讨论了一些更加复杂的并发编程问题,如线程间的协作、线程间通信、并发集合类的使用和自定义的同步工具的设计等内容。该篇通过讲解常见的并发问题和解决方案,提供了应对复杂并发场景的实践经验。 专题扩展篇主要讨论了一些与并发编程相关的主题,如并发性问题的调试与测试、程序性能调优等。这些内容能够帮助读者进一步提升对并发编程的理解和应用水平。 《Java并发编程实战》通过深入浅出的语言和大量实例,帮助读者掌握并发编程的基本概念和技术,为读者提供设计和编写高效多线程程序的实践经验。无论是Java初学者还是有一定经验的开发人员,都可以从中获得丰富的知识和实用的技巧,加速自己在并发编程领域的成长。 ### 回答3: 《Java并发编程实战》是一本经典的Java多线程编程指南,被广泛认可为学习并发编程的必读之作。本书由Brian Goetz等多位并发编程领域的专家合著,内容全面且深入浅出,适合从初学者到高级开发人员阅读。 该书分为四个部分,共16。第一部分介绍了并发编程的基础知识,包括线程安全性、对象的共享、对象组合等。第二部分讲解了如何构建可复用的并发构件,包括线程安全性、发布与初始化安全性等。第三部分深入讨论了Java并发编程中常见的问题和挑战,例如活跃性、性能与可伸缩性等。第四部分则介绍了一些高级主题,如显式锁、原子变量和并发集合等。 书中包含了大量的示例代码和实践案例,可以帮助读者更好地理解并发编程的概念和技术。此外,本书还提供了一些最佳实践和经验教训,帮助读者避免常见的并发编程陷阱和错误。 《Java并发编程实战》从理论到实践的结合非常好,书中所介绍的内容都是经过实践验证的,具有很高的可靠性和实用性。无论是初学者还是有一定经验的开发人员,都可以从中获得实际应用的知识和经验。 综上所述,如果你想系统地学习Java并发编程,了解如何编写高效、可靠的多线程代码,那么《Java并发编程实战》是一本值得推荐的书籍。它可以帮助你深入理解并发编程的原理和技术,提高自己在并发编程领域的能力和水平。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值