0

ElementClassオブジェクトのリストを含み、変更可能な次のクラスがあるElementClassとします。

public class ListContainer {
    private List<ElementClass> elements = new ArrayList<ElementClass>();

    public ListContainer(int n) {
        for (int i = 0; i < n; ++i)
            elements.add(new ElementClass());
    }

    public ElementClass getElement(String index) {
        int i = Integer.parseInt(index);
        if (i < elements.size())
            return elements.get(i);
        return null;
    }
}

ElementClassオブジェクトへの同じ参照が 2 つの異なるスレッドによって取得され、予期しない動作の危険を冒さないようにするにはどうすればよいですか? クラスを変更することでこれを行うことができますか、ListContainerそれともクラスですべてのスレッド安全対策を講じる必要がありElementClassますか?

4

2 に答える 2

1

まず、作成されたリストを何かが変更できるようにする操作がないため、(記述されている) クラスは実質的に (API の観点から) 不変です。

(リスト内のインスタンスに対して変更操作を実行できるElementClass可能性があります。ただし、それはリスト自体の変更ではありません。)

に変更操作を追加した場合は、ListContainerそれらをスレッドセーフにするために何かを行う必要があります。Listただし、内部オブジェクトが「リーク」しないと仮定すると、関連するListContainer操作を同期させるだけで十分です。


実際、記述されているクラスは 100% スレッドセーフではありません。あるスレッドがインスタンスを作成し、参照を別のスレッドに渡し、2 番目のスレッドがgetElementメソッドを呼び出したときにインスタンスのリスト状態の一貫性のないバージョンを確認する可能性があります。これは、コンストラクターの完了と後続のメソッド呼び出しの間に、先行発生または同期順序の関係がないためです。JLS 17.4.4 および 17.4.5 を参照してください。

これは、さまざまな方法で「修正」できます。例えば:

  • メソッドとして宣言getElementし、synchronized
  • 、またはelements_volatile
  • として宣言elementsfinalます。

最後のフィールドは、最終フィールドの特別なルールのために機能します。JLS 17.5 を参照してください。( が不変であることを意図している場合は、 asListContainerを宣言するのが最善の解決策です ...)elementsfinal


ElementClassオブジェクトへの同じ参照が 2 つの異なるスレッドによって取得され、予期しない動作の危険を冒さないようにするにはどうすればよいですか?

それは可能ですが、追加のデータ構造が必要になります...どのElementClassインスタンスが「チェックアウト」されたかを追跡します。また、クライアントがインスタンスを「返さない」、キューを実装しないなどの問題があります。

クラスを変更することでこれを行うことができますかListContainer...

非常に困難なだけです。上記を参照。

...または、クラスですべてのスレッドの安全対策を講じる必要がありElementClassますか?

それが最も簡単で最良のアプローチです。関連する (個々の) 操作を同期させるか、一連の操作の相互排除が必要な場合は、ロックするための「プロトコル」を考案します。(「プロトコル」はおそらく、どのロックを使用するかの「ルール」にすぎません...)

于 2013-06-15T07:17:37.653 に答える
0

授業中は安全対策が必要ElementClassです。

getElement()複数のスレッドが同時に呼び出されないようにしても、それらのスレッドは、受け取った参照を保持し、後でそれを使用する可能性があります。これにより、スレッドの安全性の問題が発生します。

つまり、異なる時間に参照を受け取ったとしても、それはまだ同じ参照であり、将来、複数のスレッドが同時に使用することができます。

于 2013-06-15T07:56:16.650 に答える