目次へ

13.新たに追加されたコレクション3

2006.06.21 株式会社四次元データ 宮澤了祐

13.1. ConcurrentMap

Mapを拡張して次のメソッドを加えています。

  • putIfAbsent(K key, V value)
    指定されたキーが値と関連付けられていない場合は、指定された値に関連付けます。
  • remove(Object key, Object value)
    キーが指定された値に現在マッピングされている場合にのみ、そのキーのエントリを削除します。
  • replace(K key, V value)
    キーが値に現在マッピングされている場合にのみ、そのキーのエントリを置換します。
  • replace(K key, V oldValue, V newValue)
    キーが指定された値に現在マッピングされている場合にのみ、そのキーのエントリを置換します。

concurrentパッケージにConcurentMapを実装したクラスjava.util.concurrentHashMapがあります。 反復子の取得のために、全体をロックする必要はありません。 更新を防ぐ必要のないアプリケーションで、同期化したCollections.synchronizedMapの代わりなどに使われます。

反復子での値の取得は、その時点において完了している変更を反映します。

{
    Map map = new ConcurrentHashMap();
    ...
    Thread thread = new Thread(new MyRunnable(map));
    thread.start();
    map.remove("value");
    ...
}

public void run() {
    Iterator itr = map.values().iterator();
    while(itr.hasNext()) {
        System.out.println(itr.next());
        try {
            Thread.sleep(1000);
        } catch(InterruptedException e)  {
        }
    }
}

上記の様に反復子取得中に要素を削除したとしてもConcurrentModificationExceptionを投げることはありません。 ただし反復子取得中の要素変更が反映されることは保証されているわけではありません。

13.2. CopyOnWriteArrayList

java.util.ArrayListをスレッドセーフにした実装です。
元の配列のコピーを作成するため、反復子作成後の変更処理が可能になりますが、 元の配列に対する変更は反復子に反映されません。

import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;

public class MyCopyOnWriteArrayList implements Runnable {

    public static void main(String[] args) {
        CopyOnWriteArrayList array = new CopyOnWriteArrayList();
    
        array.add(0,0);
        array.add(1,1);
        array.add(2,2);
        array.add(3,3);
        array.add(4,4);
    
        Thread thread = new Thread(new MyCopyOnWriteArrayList(array));
        thread.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }
        System.out.println(5 + "を追加しました。");
        array.add(5,5);
        System.out.println(4 + "を削除しました。");
        array.remove(4);
    }
  
    public MyCopyOnWriteArrayList(CopyOnWriteArrayList array) {
        this.array = array;
    }
  
    public void run() {
        Iterator itr = array.iterator();
        int i = 0;
        while(itr.hasNext()) {
            System.out.println(i + ":" + itr.next());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
        }
    }
}

これは次のように出力されます。

0:0
5を追加しました。
4を削除しました。
0:1
0:2
0:3
0:4

反復子作成後の状態が反映されていないのがわかります。

13.3. CopyOnWriteArraySet

スレッドセーフなjava.util.Setです。
CopyOnWriteArrayListと同じ性質を持ちます。

import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArraySet;

public class MyCopyOnWriteArraySet implements Runnable {

    CopyOnWriteArraySet set;
  
    public MyCopyOnWriteArraySet(CopyOnWriteArraySet set) {
        this.set = set;
    }

    public static void main(String[] args) {
        CopyOnWriteArraySet set = new CopyOnWriteArraySet();
    
        set.add(0);
        set.add(1);
        set.add(2);
        set.add(3);
        set.add(4);
    
        Thread thread = new Thread(new MyCopyOnWriteArraySet(set));
        thread.start();
    
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }
    
        System.out.println(5 + "を追加しました。"); 
        set.add(5);
        System.out.println(3 + "を削除しました。"); 
        set.remove(3);
    }

    public void run() {
        Iterator itr = this.set.iterator();
        while(itr.hasNext()) {
            System.out.println(itr.next());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
        }    
    }
}

次のように出力されます。

0
5を追加しました。
3を削除しました。
1
2
3
4

反復子作成後の変更が反映されていないことがわかります。

↑このページの先頭へ

こちらもチェック!

PR
  • XMLDB.jp