0

私は以下のコードとしてタスク リスナー モデルを作成しました。最適化またはバグ修正 (ある場合) は、特に List と Map へのアクセスで行うことができますか? このモデルでは、ユーザーのリスナーを含む複数のリストを保持するマップを作成します。ほとんどの場合、すべてのリストのサイズは約 1000 です。ここでの 2 つのポイント: 1. パフォーマンスのために、HashMap または ConcurrentHashMap を使用しますか? 2.リストをコピーして、コピーされたリストをマルチスレッドアクセスで反復するよりも良いアプローチですか?

public class TaskActionManager {

    private static final Map<String, List<TaskActionListener>> listenersMap = new ConcurrentHashMap<String, List<TaskActionListener>>();
    private static final ExecutorService executor = Executors
            .newCachedThreadPool();
    private static ReentrantLock lock = new ReentrantLock();

    public static final void addListener(TaskActionListener listener,
            TaskActionType type) {
        // type is an enum
        String key = type.name();

        List<TaskActionListener> list = listenersMap.get(key);
        lock.lock();
        try {
            // Mostly the list is not null
            if (list == null) {
                list = listenersMap.get(key);
                if (list == null) {
                    list = new ArrayList<TaskActionListener>();
                    listenersMap.put(key, list);
                }
            }
            list.add(listener);
        } finally {
            lock.unlock();
        }
    }

    public static final void removeListener(TaskActionListener listener,
            TaskActionType type) {
        List<TaskActionListener> list = listenersMap.get(type.name());
        if (list == null)
            return;

        lock.lock();
        try {
            list.remove(listener);
        } finally {
            lock.unlock();
        }
    }

    public static final void fireAction(final TaskAction action) {
        executor.execute(new Runnable() {
            @Override
            public void run() {
                List<TaskActionListener> list = listenersMap.get(action
                        .getType().name());
                if (list == null)
                    return;

                // Make a copy
                List<TaskActionListener> copy = null;
                lock.lock();
                try {
                    copy = new ArrayList<TaskActionListener>(list.size());
                    Collections.copy(list, copy);
                } finally {
                    lock.unlock();
                }

                // Iterate the copy
                if (copy != null) {
                    for (TaskActionListener listener : copy) {
                        try {
                            listener.fireAction(action);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
    }
}
4

1 に答える 1

0

パフォーマンスについては、HashMapまたはConcurrentHashMapを使用しますか?

明らかに、ConcurrentHashMapはHashMapの並行バージョンです。したがって、答えは間違いなくConcurrentHashMapです。スレッドセーフであるため、ロックする必要がないため、使用が簡単で、効率も高くなります。

これは、リストをコピーして、アクセスするマルチスレッドでコピーされたリストを繰り返すよりも優れたアプローチですか?

ConcurrentHashMapはスレッドセーフであるため、反復できるようにするためにコピーを作成する必要はありません。リストを繰り返し処理しているときにリストを(別のスレッドで)変更してもかまわない場合は、ここでリストを変更する必要がある理由がわかりません。これが最適な方法です。

詳細については、http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ConcurrentHashMap.htmlを参照してください。

ノート:

  1. イテレータは、一度に1つのスレッドのみが使用するように設計されています。
  2. Hashtableと同様ですが、HashMapとは異なり、このクラスではnullをキーまたは値として使用できません。
于 2012-08-21T10:06:36.870 に答える