在多线程中如何保证集合的安全

一、在循环中修改集合数据的问题

看代码:

List asList = Arrays.asList(1,2);
  for(int i:asList){
  asList.add(3);
  System.err.println(i);
}

我们执行这段代码会抛出这个异常 java.lang.UnsupportedOperationException,这个异常告诉我们,不支持在迭代中修改当前的集合;当你去试图移除一个元素的时候也会面临同样的问题。

为什么会这样?那我们应该如果避免这个问题呢?

1、foreach循环中是不支持对集合中的元素删除或添加的。

2、使用Arrays.asList产生的集合不支持在循环中更改;使用new ArrayList是可以的;但是我们不应该使用这种写法;因为元素的添加会移除会导致集合的长度发生变化;这极容易导致BUG;并且不易排查。

3、如果确实需要在循环中移除元素; 可以考虑使用迭代器进行操作Iterator。

二、多线程中面临的问题

通过良好的编码我们可以保证不在循环中修改集合或避免出现错误;但是如果我们在一个多线程的程序中使用了一个共享的集合;我们怎么能保证其它线和不更改集合中的元素呢?

答案是无法避免!

既然无法避免我们就要解决多个线程同时访问或修改集合的安全问题,那应该如何解决?

我们可以使用Collections.synchronizedList获取一个线程安全的集合,但是这无法保证集合不在循环的时候被其它线程所更改;答案就是加锁。要想在循环集合的时候保证线程的安全必须在循环的外层为所需要循环或迭代的集合添加锁控制;即获取当前集合持有的锁进行访问控制;

看代码:

final static List asList = Collections.synchronizedList(new ArrayList(Arrays.asList("a","b")));

public static void main(String[] args) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {Thread.sleep(150); } catch (InterruptedException e) { }
            reload();
        }
    }).start();
    synchronized (asList) {
      for(String e:asList){
        try {Thread.sleep(100);} catch (InterruptedException e1) {}
        System.out.println(e);
      }
    }
}
public static void reload(){
  asList.clear();
  asList.addAll(Arrays.asList("a","b","c"));
}

经测试代码可以正确的运行;

注意:如果你不使用Collections.synchronizedList获取一个线程安全的集合;你必须在修改集合之前首先获取集合的锁进行同步控制;或者你可以使用java.util.concurrent包下的相关线程安全的集合类。

最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 180,722评论 25赞 708
  • Collection ├List │├LinkedList │├ArrayList │└Vector │└Stac...
    AndyZX阅读 1,006评论 0赞 1
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 43,057评论 11赞 349
  • 井桐阅读 149评论 0赞 0
  • 总是想要翻开自己的记忆,总是想要追寻着过去的足迹,总感觉那些曾经发生的事情,就像是一帘幽梦,会感觉到那些过去的柔情...
    哆宝萌哒哒阅读 561评论 0赞 0

友情链接更多精彩内容