Java中是否有并发列表';是JDK吗?

Java中是否有并发列表';是JDK吗?,java,list,concurrency,Java,List,Concurrency,如何创建一个并发列表实例,在这个实例中我可以通过索引访问元素?JDK有我可以使用的类或工厂方法吗?因为获取位置和从给定位置获取元素的行为自然需要一些锁定(不能让列表在这两个操作之间进行结构更改) 并发集合的基本思想是,每个操作本身都是原子的,可以在没有显式锁定/同步的情况下完成 因此,从给定的列表中获取位于n位置的元素作为原子操作在预期并发访问的情况下没有太大意义。中存在并发列表实现。特别是。如果您只需要简单的调用同步,就可以很好地使用: List<Object> objList

如何创建一个并发列表实例,在这个实例中我可以通过索引访问元素?JDK有我可以使用的类或工厂方法吗?

因为获取位置和从给定位置获取元素的行为自然需要一些锁定(不能让列表在这两个操作之间进行结构更改)

并发集合的基本思想是,每个操作本身都是原子的,可以在没有显式锁定/同步的情况下完成


因此,从给定的
列表
中获取位于
n
位置的元素作为原子操作在预期并发访问的情况下没有太大意义。

中存在并发列表实现。特别是。

如果您只需要简单的调用同步,就可以很好地使用:

 List<Object> objList = Collections.synchronizedList(new ArrayList<Object>());
List objList=Collections.synchronizedList(new ArrayList());
ConcurrentLinkedQueue

如果你不关心有索引的访问,只想保持一个列表的插入顺序保持特性,你可以考虑一个。由于它实现了Iterable,因此在添加完所有项后,可以使用增强的for语法循环内容:

Queue<String> globalQueue = new ConcurrentLinkedQueue<String>();

//Multiple threads can safely call globalQueue.add()...

for (String href : globalQueue) {
    //do something with href
}
Queue globalQueue=new ConcurrentLinkedQueue();
//多个线程可以安全地调用globalQueue.add()。。。
for(字符串href:globalQueue){
//用href做点什么
}

CopyOnWriteArrayList是ArrayList的线程安全变体,其中 所有可变操作(添加、设置等)都由 创建基础数组的新副本

CopyOnWriteArrayList是同步列表实现列表接口及其java.util.concurrent包的一部分及其线程安全集合的并发替代方案

public class CopyOnWriteArrayList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable
公共类CopyOnWriteArrayList
实现列表、随机访问、可克隆、java.io.Serializable
CopyOnWriteArrayList是故障安全的,当在迭代过程中修改基础CopyOnWriteArrayList时,不会引发ConcurrentModificationException。请使用ArrayList的单独副本

这通常成本太高,因为复制阵列涉及到每次更新操作,因此将创建一个克隆副本。CopyOnWriteArrayList是仅用于频繁读取操作的最佳选择

/**
         * Returns a shallow copy of this list.  (The elements themselves
         * are not copied.)
         *
         * @return a clone of this list
         */
        public Object clone() {
            try {
                @SuppressWarnings("unchecked")
                CopyOnWriteArrayList<E> clone =
                    (CopyOnWriteArrayList<E>) super.clone();
                clone.resetLock();
                return clone;
            } catch (CloneNotSupportedException e) {
                // this shouldn't happen, since we are Cloneable
                throw new InternalError();
            }
        }
/**
*返回此列表的浅表副本。(a)要素本身
*不复制。)
*
*@返回此列表的克隆
*/
公共对象克隆(){
试一试{
@抑制警告(“未选中”)
CopyOnWriteArrayList克隆=
(CopyOnWriteArrayList)super.clone();
clone.resetLock();
返回克隆;
}捕获(CloneNotSupportedException e){
//这不应该发生,因为我们是可克隆的
抛出新的InternalError();
}
}

您有以下选项:

  • Collections.synchronizedList()
    :您可以包装任何
    List
    实现(
    ArrayList
    LinkedList
    或第三方列表)。使用
    synchronized
    可以保护对每个方法(读写)的访问。使用
    iterator()
    或增强for循环时,必须手动同步整个迭代。在迭代时,其他线程甚至被完全阻止读取。您还可以分别为每个
    hasNext
    next
    调用进行同步,但是可以执行
    ConcurrentModificationException

  • :修改成本很高,但请等待免费阅读。迭代器从不抛出
    ConcurrentModificationException
    ,它们在迭代器创建时返回列表的快照,即使列表在迭代时被另一个线程修改。对于不经常更新的列表很有用。更新时首选批量操作,如
    addAll
    ——内部阵列的复制次数较少

  • Vector
    :非常类似于
    synchronizedList(newarraylist())
    ,但迭代也是同步的。但是,如果向量在迭代时被另一个线程修改,迭代器可以抛出
    ConcurrentModificationException

其他选择:

  • 如果只在列表末尾添加/删除或迭代列表,则
    Queue
    Deque
    可能是另一种选择
    Queue
    只允许在一端添加,从另一端删除,
    Deque
    允许在两端添加和删除。无法通过索引进行访问。有多个实现具有比任何
    列表
    所能提供的更好的并发属性。查看中的“所有已知实现类”,那些在
    java.util.concurrent
    包中的实现是并发的。您还可以看看,它包含专门针对单个消费者或单个生产者的更快的队列实现
  • 集合。不可修改列表()
    :无需等待,线程安全,但不可修改
  • &:另一个是Java9和更高版本

如果您从未计划从列表中删除元素(因为这需要更改删除元素后所有元素的索引),则可以使用
ConcurrentSkipListMap
代替
ArrayList
,例如

NavigableMap<Integer, T> map = new ConcurrentSkipListMap<>();
您还可以通过调用
map.put(index,item)
来修改“列表”(即映射)中任何项目的值

将项目放入映射或按索引检索它们的平均成本为O(log(n)),而
ConcurrentSkipListMap
是无锁的,这使得它明显优于say
Vector
(旧同步版本的
ArrayList

您可以使用
// Add item to end of the "list":
map.put(map.size(), item);
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NavigableMap;
import java.util.Objects;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentSkipListMap;

public class ConcurrentAddOnlyList<V> implements List<V> {
    private NavigableMap<Integer, V> map = new ConcurrentSkipListMap<>();

    @Override
    public int size() {
        return map.size();
    }

    @Override
    public boolean isEmpty() {
        return map.isEmpty();
    }

    @Override
    public boolean contains(Object o) {
        return map.values().contains(o);
    }

    @Override
    public Iterator<V> iterator() {
        return map.values().iterator();
    }

    @Override
    public Object[] toArray() {
        return map.values().toArray();
    }

    @Override
    public <T> T[] toArray(T[] a) {
        return map.values().toArray(a);
    }

    @Override
    public V get(int index) {
        return map.get(index);
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        return map.values().containsAll(c);
    }

    @Override
    public int indexOf(Object o) {
        for (Entry<Integer, V> ent : map.entrySet()) {
            if (Objects.equals(ent.getValue(), o)) {
                return ent.getKey();
            }
        }
        return -1;
    }

    @Override
    public int lastIndexOf(Object o) {
        for (Entry<Integer, V> ent : map.descendingMap().entrySet()) {
            if (Objects.equals(ent.getValue(), o)) {
                return ent.getKey();
            }
        }
        return -1;
    }

    @Override
    public ListIterator<V> listIterator(int index) {
        return new ListIterator<V>() {
            private int currIdx = 0;

            @Override
            public boolean hasNext() {
                return currIdx < map.size();
            }

            @Override
            public V next() {
                if (currIdx >= map.size()) {
                    throw new IllegalArgumentException(
                            "next() called at end of list");
                }
                return map.get(currIdx++);
            }

            @Override
            public boolean hasPrevious() {
                return currIdx > 0;
            }

            @Override
            public V previous() {
                if (currIdx <= 0) {
                    throw new IllegalArgumentException(
                            "previous() called at beginning of list");
                }
                return map.get(--currIdx);
            }

            @Override
            public int nextIndex() {
                return currIdx + 1;
            }

            @Override
            public int previousIndex() {
                return currIdx - 1;
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }

            @Override
            public void set(V e) {
                // Might change size of map if currIdx == map.size(),
                // so need to synchronize 
                synchronized (map) {
                    map.put(currIdx, e);
                }
            }

            @Override
            public void add(V e) {
                synchronized (map) {
                    // Insertion is not supported except at end of list
                    if (currIdx < map.size()) {
                        throw new UnsupportedOperationException();
                    }
                    map.put(currIdx++, e);
                }
            }
        };
    }

    @Override
    public ListIterator<V> listIterator() {
        return listIterator(0);
    }

    @Override
    public List<V> subList(int fromIndex, int toIndex) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public boolean add(V e) {
        synchronized (map) {
            map.put(map.size(), e);
            return true;
        }
    }

    @Override
    public boolean addAll(Collection<? extends V> c) {
        synchronized (map) {
            for (V val : c) {
                add(val);
            }
            return true;
        }
    }

    @Override
    public V set(int index, V element) {
        synchronized (map) {
            if (index < 0 || index > map.size()) {
                throw new IllegalArgumentException("Index out of range");
            }
            return map.put(index, element);
        }
    }

    @Override
    public void clear() {
        synchronized (map) {
            map.clear();
        }
    }

    @Override
    public synchronized void add(int index, V element) {
        synchronized (map) {
            if (index < map.size()) {
                // Insertion is not supported except at end of list
                throw new UnsupportedOperationException();
            } else if (index < 0 || index > map.size()) {
                throw new IllegalArgumentException("Index out of range");
            }
            // index == map.size()
            add(element);
        }
    }

    @Override
    public synchronized boolean addAll(
            int index, Collection<? extends V> c) {
        synchronized (map) {
            if (index < map.size()) {
                // Insertion is not supported except at end of list
                throw new UnsupportedOperationException();
            } else if (index < 0 || index > map.size()) {
                throw new IllegalArgumentException("Index out of range");
            }
            // index == map.size()
            for (V val : c) {
                add(val);
            }
            return true;
        }
    }

    @Override
    public boolean remove(Object o) {
        throw new UnsupportedOperationException();
    }

    @Override
    public V remove(int index) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        throw new UnsupportedOperationException();
    }
}
// Add item after last item in the "list":
map.put(map.isEmpty() ? 0 : map.lastKey() + 1, item);

// Add item before first item in the "list":
map.put(map.isEmpty() ? 0 : map.firstKey() - 1, item);
class MyClass {
  List<MyType> myConcurrentList = new ArrayList<>();
  void myMethod() {
    synchronzied(myConcurrentList) {
      doSomethingWithList;
    }
  }
}