美文网首页
Collections.synchronizedList

Collections.synchronizedList

作者: walker113 | 来源:发表于2020-12-10 14:33 被阅读0次

大家都知道ArrayList并不是线程安全的,如果想要做到线程安全,我们可以使用 Collections.synchronizedList, 但是使用 Collections.synchronizedList后是否真的就线程安全了?

1. Collections.synchronizedList 原理

工欲善其事必先利其器,我们先来看看Collections.synchronizedList 做了什么。

  • SynchronizedList.png

    从源码来看,SynchronizedList 就是在 List的操作外包加了一层synchronize同步控制。

2. 加了 Collections.synchronizedList 后,为什么还需要使用 synchronize ?

首先我们看官方文档,可以发现, 当用户通过迭代器遍历返回列表时,必须手动同步:
It is imperative that the user manually synchronize on the returned list when traversing it via [Iterator]

  List list = Collections.synchronizedList(new ArrayList());
      ...
  synchronized (list) {
      Iterator i = list.iterator(); // Must be in synchronized block
      while (i.hasNext())
          foo(i.next());
  }

也就是说官方文档明确提出 对于 使用 Iterator遍历列表时,Collections.synchronizedList 可能发生 错误!

那除了直接使用 Iterator 要加 synchronize 保证线程安全,还有什么情况会间接使用到 Iterator吗? 那就是 for each增强for循环 ;

那我们先来写的demo验证下这种情况:

public class SynchronizedTest {
    static List<Integer> synchronizedList = Collections.synchronizedList(new ArrayList<Integer>());
    public static void main(String[] args) throws InterruptedException {
        // 先存放1000个值让iterator有值可以遍历
        for (int i = 0; i < 5; i++) {
            synchronizedList.add(i);
        }

        Thread iteratorThread = new Thread(new IteratorRunnable(synchronizedList));
        iteratorThread.start();

        TimeUnit.SECONDS.sleep(1);

        Thread modifyThread = new Thread(new ModifySynchronizeRunnable(synchronizedList));
        modifyThread.start();


    }

    static class IteratorRunnable implements Runnable {
        private List<Integer> list;
        public IteratorRunnable(List<Integer> synchronizeList) {
            this.list = synchronizeList;
        }

        @Override
        public void run() {
            while(true) {
                for (Integer i : list) {
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(i + ",");
                }
            }
        }
    }

    static class ModifySynchronizeRunnable implements Runnable {
        private List<Integer> list;

        public ModifySynchronizeRunnable(List<Integer> synchronizeList) {
            this.list = synchronizeList;
        }

        @Override
        public void run() {
            while(true) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                list.add(100);
                System.out.println("    modify list container");
            }
        }
    }
}

运行下看看结果,在使用Iteratior遍历的同时,异步修改List的结构,发现抛出了 ConcurrentModificationException 异常;

  • ConcurrentModificationException.png

那怎么解决呢?官方文档说的很清楚,我们在 迭代器遍历返回列表时,增加手动同步处理,下面是IteratorRunnable 修改后 代码,仅仅是在外层加了 synchronized

static class IteratorRunnable implements Runnable {
        private List<Integer> list;
        public IteratorRunnable(List<Integer> synchronizeList) {
            this.list = synchronizeList;
        }

        @Override
        public void run() {
            while(true) {
                synchronized (list) {
                    for (Integer i : list) {
                        try {
                            TimeUnit.SECONDS.sleep(1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(i + ",");
                    }
                }
            }
        }
    }

从运行结果来看,增加了synchronized 后,不会出现ConcurrentModificationException异常了;

  • image.png

3. 探究下for each Java的实现

先写个简单的for each语句

  • for each.java.png

    然后我们先来看看.class文件中for each

  • for each.class.png

    看到这,我们就可以确定 ,其实JAVA中的增强for循环底层是通过iterator来实现的;

相关文章

网友评论

      本文标题:Collections.synchronizedList

      本文链接:https://www.haomeiwen.com/subject/ydzcgktx.html