常用线程安全的集合总结

1.CopyOnWriteArraylist->vector

(1)支持多线程并发读取(get/遍历),只支持单线程写入(add,remove);
(2)当有修改操作发生时,会对原有的数组进行拷贝,拷贝出一个新的数组,修改操作在新的数组上发生,修改加锁。原有数组的查询操作不需要加锁保护,当修改线程执行完毕,再用新的数组替换原有的数组。
(3)把读写操作分离开,读不加锁,写加锁,用空间换取读不加锁。适合读多写少的场景。

2.ConcurrentHashMap->Hashtable

(1)1.7以前:分段锁
A.首先是一个segment的数组,每个segment的元素又是一个HashEntry数组,Node数组中又存放了链表。
B.锁定以segment为单位
C.初始化时,会创建所有segment数组的元素,而segment数组不能扩容,占用内存多
D.Put操作会锁住key对应的segment,元素放入HashEntry的数组+链表结构中,元素放入链表头
E.Get操作无锁,扩容会加锁
(2)1.8做了修改:
A.Hashtable是锁住了整个map集合,而ConcurrentHashMap,它只会锁住map集合中的一个桶,根据桶的多少,可以进一步提高并发度,只要读写操作落在不同的桶里,操作就可以并行执行
B.初始化数组时,懒惰初始化
C.当容量小于64首先尝试扩容,当超过这个容量并且链表大于8,会将链表树化,树化过程中会锁住链表头
D.Put操作会锁住链表头,新加的元素放入链表尾部
E.Get操作不需要加锁,仅需要用cas(乐观锁)保证元素的可见性
F.扩容以链表为单位扩容,当扩容时有多个线程来同时访问,这些线程会协助扩容

3.ConcurrentSkipListMap

数据结构:跳跃表
类似于之前LinkedHashMap,都可以保持元素遍历的顺序和放入的顺序是一致的
LinkedHashMap非线程安全,ConcurrentSkipLIstMap线程安全

4.BlockingQueue 阻塞队列

经常用来实现生产消费模式,来解耦生产者、消费者线程

```java
BlockingQueue<Item> queue = new LinkedBlockingDeque<>(5);
Thread t1 = new Thread(()-> {
    try {
        for (int i = 0; i < 6; i++) {
            Item item = new Item("产品" + i);
            queue.put(item);
            System.out.println(Thread.currentThread().getName() + "生产了商品:" + item.name);
            Thread.sleep(1000);
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});
Thread t2 = new Thread(()-> {
    try{
        for (int i = 0; i < 0; i++) {
            Item item = queue.take();
            System.out.println(Thread.currentThread().getName() + "消费了商品:" + item.name);
        }
    } catch (Exception e) {

    }
});
```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值