Java容器

容器——同步容器与并发容器

一,同步容器

vector ,hashtable:JDK提供的同步容器。
(Vector:实现了List接口,Vector实际上就是一个数组,和ArrayList类似,但是Vector中的方法都是synchronized方法,即进行了同步措施。但是在多线程情况下也会有不安全的情况。如下面的列子)
hashTable:实现同步是利用synchronized关键字进行锁定的,其是针对整张哈希表进行锁定的,即每次锁住整张表让线程独占,在线程安全的背后是巨大的浪费。
collections. synchronizedXXX:本质是对相应的容器进行包装。

同步容器的缺点:

在单独使用里面的方法的时候,可以保证线程安全,但是在复合操作的时候则需要额外的加锁来保证线程的安全。

复合操作包括迭代(反复获取元素,直到容器中的最后一个元素)、导航(根据一定顺序查找下一元素)、条件运算(比如缺少即加入)。这种复合操作对于本身是线程安全的同步容器来说,如果多个线程并发访问,可能就会出现问题。

import java.util.Iterator;
import java.util.Vector;

public class VectorDemo {
    public static void main(String[] args) {
        Vector<String> vector = new Vector();
        for (int i = 0; i < 1000; i++) {
            vector.add("demo"+i);
        }

        Iterator<String> iterable = vector.iterator();
        while (iterable.hasNext()){
            String str = iterable.next();
            if(str.equals("demo3")){
            //复合操作,多线程情况下不安全
                System.out.println("str = " + str);
                iterable.remove();
            }
        }
    }

}

使用Iterator迭代容器或使用for-each遍历容器,在迭代的过程中修改容器会抛出concurrentModificationException异常。想要避免该异常,则迭代过程中就必须得加锁。但若是迭代容器比较大数据比较多时,则迭代时间会过长,其他线程等待时间将大大增加,从而极大降低性能。

二,并发容器

1,copyOnwrite,BlockingQueue:根据具体场景进行设计,尽量避免使用锁,提高容器的并发访问性。

copyOnwrite:实现就是写时复制。通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,(这里要配合上volatile关键字的使用,核心就是让一个变量被写线程给修改之后,立马让其他线程可以读到这个变量引用的最近的值,这就是volatile最核心的作用)再将原容器的引用指向新的容器。
BlockingQueue:基于queue实现FIFO的队列,

2,LInkedBlockingQueue:内部由单链表实现,只能从head取元素,从tail添加元素。添加元素和获取元素都有独立的锁,也就是说LinkedBlockingQueue是读写分离的,读写操作可以并行执行。LinkedBlockingQueue采用可重入锁(ReentrantLock)来保证在并发情况下的线程安全。
LInkedBlockingQueue:适用于做生产者和消费者的中间商。
remove():调用poll方法,但是为空是会抛出异常。
poll():为空时直接返回null。
take():队列为空时,会进入等待状态。(在中间商中常用该方法)

add():调用offer方法,满的时候继续加入会抛出异常。
offer():队列满的时候,直接入队失败。
put():队列为空时会进入等待状态。(在中间商中常用该方法)

3,ConcurrentHashMap:线程安全的map,其中利用了锁分段的思想提高了并发度。(这是JDK1.7的
1.7与1.8区别的相关源码分析
(1)1.7 使用segment分段锁,每个锁维护一个Node数组
1.8 给Node加锁,锁粒度更小,并发性能更佳,进一步减少了并发冲突
(2)1.7使用的是 segment+数组+链表
1.8 使用的是数组+链表+红黑树,在哈希冲突较多的情况下,有较好的查询性能
ConcurrentHashMap与hashTable的区别:
在这里插入图片描述

ConcurrentHashMap的实现方式,单独锁住每一个桶(segment).ConcurrentHashMap将哈希表分为16个桶(默认值),诸如get(),put(),remove()等常用操作只锁当前需要用到的桶,而size()才锁定整张表。原来只能一个线程进入,现在却能同时接受16个写线程并发进入(写线程需要锁定,而读线程几乎不受限制),并发性的提升是显而易见的。

hashMap是线程不安全的:在多线程环境下,使用HashMap进行put操作会引起死循环,导致CPU利用率接近100%,所以在并发情况下不能使用HashMap。
HashMap在并发执行put操作时会引起死循环,是因为多线程会导致HashMap的Entry链表形成环形数据结构,一旦形成环形数据结构,Entry的next节点永远不为空,,就会产生死循环获取Entry。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值