Java同時プログラミング学習レコード4

8605 ワード

オブジェクトの結合


クラスを構築するモードを検討し、クラスがスレッドの安全になりやすいようにします.

スレッドのセキュリティを設計するクラス


スレッドの安全なクラスを設計するプロセスには、オブジェクトのステータスがどの変数から構成されるかを決定する-変数;オブジェクトの状態を制限する不変の制約を決定します.-不変の制約.-同時アクセス・オブジェクトのステータスを管理するポリシー-事後条件を設定します.
不変制約:intの値範囲など、状態が合法であるか非合法であるかを判定するために使用され、状態に適用される制約である.
後験条件:ある状態遷移が合法かどうかを指摘することは、状態操作に加わる制約である.
上記の2つは、追加の同期およびパッケージングを導入する必要がある.
≪グループ|Combination|oem_src≫:オブジェクトを別のオブジェクトの内部にカプセル化します.
組み合わせにより、カプセル化されたオブジェクトのすべてのアクセスパスが知られ、アプリケーションシステム全体のアクセスオブジェクトよりもアクセスパスの分析が容易になり、その後、様々な適切なロックと組み合わせて、プログラムがスレッドで安全に他の非スレッドで安全なオブジェクトを使用できることを確保することができる.
同時領域では、組合せはスレッドの安全を保証するためのスレッド制限である.

Javaモニタモード


すべての可変状態をカプセル化し、オブジェクトの内部ロックを使用して保護するスレッド制限原則.例:
public class PrivateLock {
    private final Object myLock = new Object();
    @GuardedBy("myLock") Widget widget;

    void someMethod() {
        synchronized (myLock) {
            // Access or modify the state of widget
        }
    }
}

委任スレッドのセキュリティ


スレッドセキュリティのコンポーネントのいくつかを組み合わせたコンポーネントは、必ずしもスレッドセキュリティではありません.たとえば、これらのスレッドの安全なサブコンポーネントには依存性があります.コードを参照:
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
        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
        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());
    }
}

2つのスレッドがある場合、setLowerとsetUpperにそれぞれアクセスすると、スレッドセキュリティの問題が発生する可能性があります.
1つのクラスが互いに独立したスレッドセキュリティのステータス変数を複数組み合わせており、クラスの操作に無効なステータス変換が含まれていない場合にのみ、スレッドセキュリティをこれらのステータス変数に委任できます.

既存のスレッドセキュリティクラスに機能を追加


Java独自のスレッドセキュリティクラスを再利用するには、難易度、リスク、メンテナンスにかかわらず、新しいクラスを作成するよりも優れています.たとえば、リストに機能を追加します.欠けている場合は追加します.すなわちlistにこの要素があるかどうかを判断し、ない場合は追加する.この場合、チェック-この複合操作を実行することに関連し、以前の同期ポリシーに従って、この操作にロックをかけて原子的な操作にすることができますが、ソースコードは修正できないので、他の方法を探すしかありません.ここでは、組み合わせたり、継承したりすることができます.たとえば、継承:
@ThreadSafe
public class BetterVector <E> extends Vector<E> {
    // When extending a serializable class, you should redefine serialVersionUID
    static final long serialVersionUID = -3963416950630760754L;

    public synchronized boolean putIfAbsent(E x) {
        boolean absent = !contains(x);
        if (absent)
            add(x);
        return absent;
    }
}

ただし、組み合わせ(ここでは元の機能のスレッドがサブコンポーネントに安全に委任されているだけを指す)では、他の操作が必要であり、直接方法で同期することはできません.Q 1操作はhelperクラスパッケージのlistの他の方法とputifを保証できないため.を選択して設定できます.
@NotThreadSafe//Q1 , 
class BadListHelper  {
    public List list = Collections.synchronizedList(new ArrayList());

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

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

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

もう1つの組み合わせは、サブコンポーネントオブジェクトがスレッドが安全かどうかに依存することなく、組み合わせられたオブジェクト内のすべてのリスクのある方法に内部ロックを加えることです.
@ThreadSafe
public class ImprovedList<T> implements List<T> {
    private final List list;

    public ImprovedList(List list) { this.list = list; }

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

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

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

ドキュメントを書くことは、とても重要です.
//下編待ち

メインリファレンス:自_Java Concurrency in Practice