第一个线程是使用对象连续填充集合。第二个线程需要遍历这些对象,但不会更改集合。
目前我使用Collection.synchronized
使其成为线程安全的,但有一种快速的方法吗?
很简单:只要按下鼠标按钮,第一个线程(ui)就会将鼠标位置连续写入ArrayList。第二个线程(渲染)根据列表绘制一条线。
答案 0 :(得分:3)
使用BlockingQueue的java.util.concurrent.ArrayBlockingQueue.ArrayBlockingQueue实现。它非常适合您的需求。
它完全适合生产者 - 消费者案例,因为这是您的个案。
您还可以配置访问策略。 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中的并发: -
使用Collections.synchronizedList(list) - 目前您正在使用它。
CopyOnWriteArrayList - 与ArrayList类很相似,只是在修改列表时,不是修改底层数组,而是创建一个新数组,旧数组将被丢弃。它会比1慢。
使用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<>())