Java中的同步列表/映射(如果只有一个线程正在写入它)

时间:2015-08-19 13:08:06

标签: java multithreading collections synchronized java.util.concurrent

第一个线程是使用对象连续填充集合。第二个线程需要遍历这些对象,但不会更改集合。

目前我使用Collection.synchronized使其成为线程安全的,但有一种快速的方法吗?

更新

很简单:只要按下鼠标按钮,第一个线程(ui)就会将鼠标位置连续写入ArrayList。第二个线程(渲染)根据列表绘制一条线。

6 个答案:

答案 0 :(得分:3)

使用BlockingQueue的java.util.concurrent.ArrayBlockingQueue.ArrayBlockingQueue实现。它非常适合您的需求。

  1. 它完全适合生产者 - 消费者案例,因为这是您的个案。

  2. 您还可以配置访问策略。 Javadoc解释了这样的访问策略:

      

    如果为真,那么插入或删除时阻塞的线程的队列访问将按FIFO顺序处理;如果为false,则未指定访问顺序。

答案 1 :(得分:2)

即使您同步列表,它在迭代时也不一定是线程安全的,因此请确保在其上进行同步:

synchronized(synchronizedList) {
    for (Object o : synchronizedList) {
        doSomething()
    }
}

编辑:

这是一篇关于此事的非常清晰的文章: http://java67.blogspot.com/2014/12/how-to-synchronize-arraylist-in-java.html

答案 2 :(得分:1)

如评论中所述,您需要在此列表上进行显式同步,因为迭代不是原子的:

List<?> list = // ...

主题1:

synchronized(list) {
    list.add(o);   
}

主题2:

synchronized(list) {
    for (Object o : list) {
        // do actions on object
    }
}

答案 3 :(得分:1)

我目前可以考虑使用3个选项来处理ArrayList中的并发: -

  1. 使用Collections.synchronizedList(list) - 目前您正在使用它。

  2. CopyOnWriteArrayList - 与ArrayList类很相似,只是在修改列表时,不是修改底层数组,而是创建一个新数组,旧数组将被丢弃。它会比1慢。

  3. 使用ReentrantReadWriteLock创建自定义ArrayList类。您可以围绕ArrayList类创建包装器。读取/迭代/循环时使用读锁定,并在数组中添加元素时使用写锁定。 例如: -

    import java.util.List;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReadWriteLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    public class ReadWriteList<E> {
    
        private final List<E> list;
        private ReadWriteLock lock = new ReentrantReadWriteLock();
        private final Lock  r =lock.readLock();
        private final Lock  w =lock.writeLock();
    
        public ReadWriteList(List<E> list){
            this.list=list;
        }
    
        public boolean add(E e){
    
            w.lock();
            try{
                return list.add(e);
            }
            finally{
            w.unlock();
            }
        }
    
        //Do the same for other modification methods
    
        public E getElement(int index){
            r.lock();
            try{
    
                return list.get(index);
            }
            finally{
                r.unlock();
            }   
        }
    
        public List<E> getList(){
            r.lock();
            try{
            return list;
            }
            finally{
            r.unlock();
            }   
        }
        //Do the same for other read methods
    }
    

答案 4 :(得分:0)

如果您的阅读频率远高于写作,则可以使用CopyOnWriteArrayList

答案 5 :(得分:0)

List而不是Set符合您的需求?

如果是,您可以使用Collections.newSetFromMap(new ConcurrentHashMap<>())