首页 > 技术文章 > 并发容器的前世今生是怎样的?

YXBLOGXYY 2022-03-31 12:17 原文

1)我们java中的容器大致可以分为哪几类?

  • list set map queue

2)线程安全容器的进化史是怎样的?

  • 1.5之前,我们的线程安全容器都是用synchronized修饰的,这样的话串行度很高,程序的性能就比较拉跨。这时的容器 只能叫做同步容器

  • 1.5之后,我们用了写时复制技术,保障线程安全的同时 ,还提高 了程序执行的并发度,这时容器可以叫并发容器了 。

2)我们的有些容器像arraylist,hashmap啊都是线程不安全的,那思考一下我们把一个线程不安全的容器怎样可以变为线程安全的容器?

  • 我们可以用面向对象的思想,把这个容器封装到类里面,然后对外提供的方法都是用关键字synchronized修饰的,但是注意两个方法组合起来的话是不能保证线程安全的啊,我们的snchronized只能保证单个方法的线程安全。

     
     SafeArrayList<T>{
       //封装ArrayList
       List<T> c = new ArrayList<>();
       //控制访问路径
       synchronized
       T get(int idx){
         return c.get(idx);
      }
     
       synchronized
       void add(int idx, T t) {
         c.add(idx, t);
      }
     
       synchronized
       boolean addIfNotExist(T t){
         if(!c.contains(t)) {
           c.add(t);
           return true;
        }
         return false;
      }
     }

     

3)上面我们说到了写时复制技术,那我们来看一下这是一种什么技术,底层是怎样实现的?

 

 

 

 

  • 底层有一个数组,有一个迭代器指向我们数组的首个元素。当我们要 进行写操作的时候,数组 会复制一份出来,然后写操作都是在复制出来的这一份数组上面进行,那读的话 是在原数组上面进行的,不受我写操作的影响。之后我们再把指向原数组的指针指到写完的这个数组,那我们就 写操作结束。

  • 这种技术有优点有缺点,优点是提高了并行能力 ,缺点的话适用的场景是读多写少的场景,并且能容忍短暂的数据不一致 问题。

4)用了写时复制技术实现的容器有哪些呢?

 

 

  • 其中的skiplist是跳表的意思,concurrentskiplistmap的 话 代表我key是有序的。

5)思考这样一个问题:在 1.8 之前的版本里并发执行 HashMap.put() 可能会导致 CPU 飙升到 100%

  • Java7中的HashMap在执行put操作时会涉及到扩容,由于扩容时链表并发操作会造成链表成环,所以可能导致cpu飙升100%。 

推荐阅读