java并发容器

首先我们先看下几个概念

  1. 高并发和多线程的区别?
    多线程:是java的特性
    高并发::不是java特有的东西,和语言无关
  2. 同步和异步
    同步:任务进行存在顺序(等待)
    异步:多任务进行没有顺序(无需等待)
  3. 并发和并行
    并发:多个任务交替进行
    并行:多个任务同时进行

什么是同步容器

通过synchronized关键字修饰的容器,保证同一个时刻内只有一个线程在使用这个容器,从而使得容器线程安全

什么是并发容器

允许多线程同时使用容器,并且保证线程安全.而为了达到尽可能的提高并发,java并发工具包中采用了多种优化方式来提高并发容器的执行效率. 核心: 锁,cas,cow(读写分离),分段锁

同步容器

Vector: 和Arraylist一样实现的List接口,区别在于Vector在可能出现线程不安全的所有方法都用了synchronized进行修饰
Stack: 是Vector的子类,Stock实现的是先进后出的栈,入栈,出栈都用了synchronized的关键字修饰
HashTable:实现Map接口,实现的功能和HashMap基本一致(HashTable不可能出现null,HashMap的键值可以存在null),HashTable也使用了synchronized修饰了方法

ArrayList,HashSet,HashMap这些都是线程不安全的,如何将这些线程不安全的转换成线程安全的呢?
Collections提供了同步集合类

 List<Object> objects = Collections.synchronizedList(new ArrayList<>());
 Map<Object, Object> objectObjectMap = Collections.synchronizedMap(new HashMap<>());
 Set<Object> objects1 = Collections.synchronizedSet(new HashSet<>());
  • 但是这种方式在多线程处理时效率是非常低的,在jdk1.5之后就提供的并发包,就可以解决多线下处理效率低的问题

CopyOnWriteArrayList : 写时复制容器.写的是时候,会先复制一个容器
读: 从原来容器读
写: 把数据写到新的容器中
List.add()方法

public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
        
            Object[] elements = getArray();
            int len = elements.length;
            //这个是将原数组拷贝一份
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            //将新的数组替换原来的数组
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }

List.remove()方法

public E remove(int index) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            E oldValue = get(elements, index);
            int numMoved = len - index - 1;
            if (numMoved == 0)
            //如果是移除最后一个元素,拷贝(0,len-1)的集合对象
                setArray(Arrays.copyOf(elements, len - 1));
            else {
                Object[] newElements = new Object[len - 1];
                //将原数组中从索引0开始拷贝index个元素,放到新中,从索引0开始
                System.arraycopy(elements, 0, newElements, 0, index);
                //将原数组中从index+1号元素开始拷贝,放到新数组中,拷贝len - index - 1个原素
                //两次加起来一共拷贝len-1个元素
                System.arraycopy(elements, index + 1, newElements, index,
                                 numMoved);
                //替换原数组
                setArray(newElements);
            }
            return oldValue;
        } finally {
            lock.unlock();
        }
    }

list.get()方法

 public E get(int index) {
         //getArray()获取当前集合
        return get(getArray(), index);
    }

//获取集合对应索引的元素
private E get(Object[] a, int index) {
        return (E) a[index];
    }

以上是copyOnWriteArrayList的一些方法的源码,总结下来有两个缺点
1 占用系统资源,频繁创建对象
2 数据一致性问题: 只能保证最终一致性

ConcurrentHashMap :
在JDK1.7中:数组+链表+分段锁
在JDK1.8中:数组+链表+红黑树

1、当一个位置有多个元素的时候,ConcurrentHashMap优先采用链表的形式存储
2、如果链表的元素个数大于8个,并且数组的长度小于64,则扩容
3、如果链表的元素个数大于8个,并且数组的长度大于64,会将该节点的链表转换成红黑树

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值