Search on the blog

2013年9月11日水曜日

synchronizedなcollection、immutableなcollectionを作る

 最近「スレッドセーフ」、「immutable」、「副作用」といったテーマがあついです。

いろいろ調べていたら、Javaにはcollection framework をスレッドセーフなインスタンスに変換してくれる機能や、mutableなクラスのインスタンスをimmutableにしてくれるような機能があるようです。

これは素晴らしい。参照側がきちんとinterfaceでインスタンスを見ていれば((例)HashMapのインスタンスはMap型の参照変数に格納していればという意味)、変換を行っても外部には影響しないというのがよくできてるなーと思います。

適当にサンプルを書いて動作確認してみたので、載せておきます。

mutableなオブジェクトをimmutableにする例
参照型の変数にfinalをつけても、参照先のオブジェクトの内容は書き換えることが出来ることに注意です。これを防ぐためにはオブジェクトをimmutableにすればよいです。
package com.kenjih.test;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class Clazz {
    @SuppressWarnings("serial")
    // 商品コード-商品名を格納するマップ(外部から参照できるけど変更できないようにしたい)
    public static final Map<String, String> MASTER_DATA = Collections.unmodifiableMap(
        new HashMap<String, String>() {
            {
                put("12456", "Stratocaster");
                put("33333", "Telecaster");
                put("43254", "Les Paul");
            }
        }
    );
    
    public void run() {
        System.out.println(Clazz.MASTER_DATA.get("12456"));
        System.out.flush();
        Clazz.MASTER_DATA.put("77777", "Mustang");
    }
    
    public static void main(String[] args) {
        new Clazz().run();
    }
}

スレッドセーフでないオブジェクトをスレッドセーフにする例
ArrayListをスレッドセーフにしています。List型の変数に格納するのがポイントです。
package com.kenjih.test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Hoge {
    private List<Integer> list = Collections.synchronizedList(new ArrayList<Integer>());
    private static final int THREAD_NUM = 100;
    
    class MyThread extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 1000; i++) {
                list.add(i);                    
            }
        }
    }

    public void run() throws InterruptedException {
        MyThread[] threads = new MyThread[THREAD_NUM];
        
        for (int i = 0; i < THREAD_NUM; i++) {
            threads[i] = new MyThread();
            threads[i].start();
        }
        
        for (int i = 0; i < THREAD_NUM; i++) {
            threads[i].join();
        }
        
        System.out.println("list size = " + list.size());
    }

    public static void main(String[] args) throws InterruptedException {
        new Hoge().run();
    }
}

0 件のコメント:

コメントを投稿