美文网首页
[Java 并发] 并发编程实战笔记-对象的组合

[Java 并发] 并发编程实战笔记-对象的组合

作者: 但莫 | 来源:发表于2017-05-22 08:30 被阅读0次

编写线程安全的代码时,我们不希望对每次内存访问都进行分析一确保程序是线程安全的,而是希望将一些现有的安全组建组合为更大规模的组建或程序。下面介绍一些组合模式,这些模式能够使一个类更容易成为线程安全的,并且在维护这些类是不会无意中破坏类的安全性保证的。

设计线程安全的类

在设计线程安全类的过程中,需要包含以下三个基本要素:

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

对象的状态是由对象的域组成的,有0-n个不等,如果域都是基本类型,那这些域构成对象的全部状态,如果有引用类型,那么该对象的状态包括被引用对象的域(如LinkedList的状态包括链表中所有节点对象的状态)。

实例封装

如果对象不是线程安全的额,那么可以通过多种技术使他在多线程程序中安全的使用。

  1. 可以确保该对象只能由单个线程访问(线程封闭),如JDBC Connection对对象,ThreadLocal。
  2. 通过一个锁来保护该对象的所有访问(Java监视器模式),如PersonSet,代码在后面。
  3. 封装对象,只暴露可访问的方法。与对象由整个程序访问的情况比,更容易对代码进行分析。如Collections中的UnmodifiableCollection。
// mySet不会逸出,唯一的外部引用就是PersonSet,使用Java监视器来封装能确保线程安全。
@ThreadSafe
    public class PersonSet {
        @GuardedBy("this")
        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);
        }
    }

将数据封装在对象内部,可以将数据的访问限制在对象的方法上,从而更容易确保线程的访问数据室总能持有正确的锁。

线程安全性的委托

我们可以把线程安全委托给先有的线程安全类,这样我们的代码阿九不用关心线程安全的问题了额。这里有两种情况:

  1. 如果委托给单独的线程安全类,能保证线程安全。如,我们可以使用ConcurrentHashMap保存线程共享数据。
  2. 如果委托给两个或两个已上的线程安全类,如果存在竞态条件,需要额外的同步机制保证;如果分别表示独立的状态,可以不使用额外的同步机制即可保证线程安全。
  3. 在现有线程安全类中添加功能,叫作客户端加锁。这种机制是派生类的行为与基类耦合在一起,破坏了基类的同步策略,使用时需要特别小心

示例代码:

// 情况2,需要增加同步机制保证 check-than-act
public class NumberRange {
    // INVARIANT: lower <= upper
    private final AtomicInteger lower = new AtomicInteger(0);
    private final AtomicInteger upper = new AtomicInteger(0);
    public void setLower(int i) {
        // Warning -- unsafe check-then-act , need a lock
        if (i > upper.get())
            throw new IllegalArgumentException(
                    "can't set lower to " + i + " > upper");
        lower.set(i);
    }
    public void setUpper(int i) {
        // Warning -- unsafe check-then-act , need a lock
        if (i < lower.get())
            throw new IllegalArgumentException(
                    "can't set upper to " + i + " < lower");
        upper.set(i);
    }
    public boolean isInRange(int i) {
        return (i >= lower.get() && i <= upper.get());
    }
}

小结

这一章介绍了实现线程安全类是采用的一些技术。

  1. 线程安全可以委托给现有的线程安全类。
  2. 委托是创建线程安全的一个有效策略。
  3. 值需要让现有的线程安全类管理所有的状态即可
  4. 当需要使用多个线程安全类保存状态是,需要额外的同步机制保证。

相关文章

网友评论

      本文标题:[Java 并发] 并发编程实战笔记-对象的组合

      本文链接:https://www.haomeiwen.com/subject/xywcxxtx.html