Java同時プログラミング実戦III


このシリーズの文章はブロガーの学習ノートで、転載を禁止して、読書交流群:946541246

文書ディレクトリ

  • Java同時プログラミング実戦五章学習
  • シンクロコンテナクラスの問題
  • 反復器とC o n c u r r e ntModificationException
  • Java同時プログラミング実戦5章学習


    コンテナクラスを同期する問題

    public class UnsafeVectorHelpers {
        public static Object getLast(Vector list) {
            int lastIndex = list.size() - 1;
            return list.get(lastIndex);
        }
    
        public static void deleteLast(Vector list) {
            int lastIndex = list.size() - 1;
            list.remove(lastIndex);
        }
    }
    

    上のコードで問題があります.スレッドAが10要素を含むVectorでgetLastを呼び出し、スレッドBが同じVectorでdeleteLastを呼び出すと、ArrayIndexOutOfBoundsExceptionの異常修復が発生します.クライアントロックを使用して、原子操作であることを保証します.
    public class SafeVectorHelpers {
        public static Object getLast(Vector list) {
            synchronized (list) {
                int lastIndex = list.size() - 1;
                return list.get(lastIndex);
            }
        }
    
        public static void deleteLast(Vector list) {
            synchronized (list) {
                int lastIndex = list.size() - 1;
                list.remove(lastIndex);
            }
        }
    }
    

    同様に、次のプログラムでも問題が発生します.他のスレッドが同時にVectorを変更している場合は、面倒になる可能性があります.Vectorを反復すると、別のスレッドが要素を削除し、この2つの操作が交互に実行されると、この反復方式はArrayIndexOutOfBoundsException異常を放出します.
    Vector vector = null;
            for (int i = 0; i < vector.size(); i++) {
                doSomething(vector.get(i));
            }
    

    解決:
    Vector vector = null;
            synchronized (vector) {
                for (int i = 0; i < vector.size(); i++) {
                    doSomething(vector.get(i));
                }
            }
    

    反復器とC o n c u r r e ntModificationException


    for-eachループ構文では、コンテナクラスを反復する標準的な方法はIteratorを使用します.他のスレッドが同時にコンテナを変更している場合は、ConcurrentModificationException例外が放出されます.
    List objects = Collections.synchronizedList(new ArrayList());
            // ...
            //  ConcurrentModificationException
            for (Object o : objects) {
                //  doSomething
            }
    

    ConcurrentModificationExceptionを回避するには、反復中にコンテナのロックを保持する必要があります.コンテナの規模が大きい場合、または各要素で操作を実行する時間が長い場合、これらのスレッドは反復中にキャパシタをロックしたくない場合に長時間待機します.代わりに、コンテナをクローンし、コピー上で反復します.
    toString、hashCode、equalなどのメソッドも間接的に反復操作を実行し、コンテナが別のコンテナの要素またはキー値として使用されると、このような状況が発生します.同様にcontainsAll,removeAll,retainAllなどの方法や,コンテナをパラメータとする構造関数は,コンテナを反復する.これらの間接的な反復操作はすべてConcurrentModificationExceptionから放出される可能性があります.