博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java并发集合知识点(二)
阅读量:7063 次
发布时间:2019-06-28

本文共 2314 字,大约阅读时间需要 7 分钟。

我们平时写程序需要经常用到集合类,比如ArrayList、HashMap等,但是这些集合不能够实现并发运行机制,这样在服务器上运行时就会非常的消耗资源和浪费时间,并且对这些集合进行迭代的过程中不能进行操作,否则会出现错误,例如下面程序:

[java] public class CollectionModifyExceptionTest {     public static void main(String[] args) {         Collection users = new ArrayList();         users.add(new User("张三",28));            users.add(new User("李四",25));                    users.add(new User("王五",31));            Iterator itrUsers = users.iterator();         while(itrUsers.hasNext()){             System.out.println("正在执行!");             User user = (User)itrUsers.next();             if("李四".equals(user.getName())){                 users.remove(user);             } else {                 System.out.println(user);                            }         }     } }

       程序在执行过程中会报错, 因为定义了一个ArrayList类型的集合,但是在对集合进行迭代的时候又出现了users.remove(user),即从集合从删除数据,对于普通的集合来说这是不允许的,Java 5以后出现的并发集合类就是专门针对普通集合出现不能并发和不能在迭代过程中修改数据等问题而出现的。

 并发集合类主要有:

ConcurrentHashMap;          ConcurrentSkipListMap;              ConCurrentSkipListSet;           CopyOnWriteArrayList; CopyOnWriteArraySet;         ConcurrentLinkedQueue;

 

ConcurrentLinkedQueue

ArrayBlockingQueue和LinkedBlockingQueue都是使用lock来实现的,也就是阻塞式的队列,而ConcurrentLinkedQueue使用CAS来实现,是非阻塞式的“lock-free”实现。

ConcurrentLinkedQueue源代码的实现有点复杂,具体的可看这篇文章的分析:

http://www.infoq.com/cn/articles/ConcurrentLinkedQueue

ConcurrentHashMap

HashMap不是线程安全的。

HashTable容器使用synchronized来保证线程安全,在线程竞争激烈的情况下HashTable的效率非常低下。

ConcurrentHashMap采用了Segment分段技术,容器里有多把锁,每把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率。

CopyOnWriteArrayList

CopyOnWrite容器即写时复制的容器。往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。类似的有CopyOnWriteArraySet。

public boolean add(T 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();    }} final void setArray(Object[] a) {    array = a;}

读的时候不需要加锁,如果读的时候有多个线程正在向ArrayList添加数据,读还是会读到旧的数据,因为写的时候不会锁住旧的ArrayList。

public E get(int index) {    return get(getArray(), index);}

 

转载地址:http://awill.baihongyu.com/

你可能感兴趣的文章
ASP.NET CORE下取IP地址
查看>>
Jenkins忘记密码的修复方法(Windows/Linux)
查看>>
如何给域名配置https证书
查看>>
mysql数据库的备份与恢复(附测试截图)
查看>>
linux系统部署mongodb数据库
查看>>
区块链应用 | 最全区块链生态图谱发布,一张图看清2400个典型项目
查看>>
AI又来抢饭碗!专利显示迪士尼要开发卡通机器人
查看>>
ajax跨域
查看>>
第二届互联网安全责任论坛举办泛娱乐安全成关注焦点
查看>>
关于阵列卡的配置参数Cache Policy(缓存策略)
查看>>
docker的Dockerfile指令
查看>>
【转】CentOS 7. × 系统及内核升级指南
查看>>
基础练习 数列排序
查看>>
Batch containing 11 record(s) expired due to timeout while requesting metadata
查看>>
Android Activity的生命周期
查看>>
Azure Web应用中设置静态虚拟目录的方法(比如部署Django需要用到)
查看>>
CentOS6.5配置网络
查看>>
【Linux】Ubuntu配置服务自启动 sysv-rc-conf
查看>>
oracle10g创建用户
查看>>
mybatis-入门
查看>>