前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >集合中的线程初体验

集合中的线程初体验

作者头像
用户5745563
发布2019-07-04 14:52:42
3560
发布2019-07-04 14:52:42
举报
文章被收录于专栏:码思客码思客

java零基础入门-高级特性篇(四) HashSet 和 Collections

本章继续讲集合,先来看看Set集合。Set集合的特点,1:无序,2:无重复。上一章讲了HashMap,最后提到HashSet的底层实现其实就是HashMap。那么为什么用HashMap就可以实现无序和不重复,下面看看具体如何使用HashMap实现HashSet。

hashset和hashmap的区别

hashset底层用hashmap实现,那为什么不直接用hashmap就完了,非要整个hashset出来?

集合

如果有这个问题,可以回头看看前面讲的集合框架的设计。设计hashset是用来保存那种不需要使用下标操作元素,并且不能重复的集合。set集合的元素和List集合的元素一样,都是一个对象。而hashmap的元素是key-value键值对,因为数据存储类型不同,所以需要将set和map区分开来。看一下图,帮助回忆一下。

hashmap如何实现hashset

Set集合最重要的一个方法就是add(E e),如何往一个Set集合添加元素,了解了添加元素的原理,查找元素理解起来就简单许多。hashset的add方法,用的就是是hashmap的put方法。下面是源代码:

map.put(e,PRESENT) == null

这里需要重点理解的是,一个对象如何存入一个key-value。从上面这句代码中,可以发现,在往set集合添加元素的时候,这个元素e被用来当做map的key,而value是一个常量。

为什么直接将对象作为key呢?因为hashmap使用哈希算法对key进行计算,计算后的结果就是底层数组的位置,所以当使用hashset的时候,需要对放进set的对象进行哈希计算,至于value,hashset不关心。

hashmap的key的特性就是不会重复,后添加相同的数据会将前一个数据覆盖掉。正好满足了set集合不重复的特性,所以直接用hashmap即可以满足hashset集合的要求。

关系

其实这里容易绕晕的是几个底层实现的结构,这里用一个图来说明一下。HashSet利用HashMap的Key的特性来实现,而HashMap是利用数组和链表的特性来实现,这样应该明白这几个结构之间的关系了吧。

这次hashset真的讲完了。

Collections工具

使用集合存放数据的时候,会有很多情况要对集合进行操作。特别是List集合,因为List集合的有序性,会需要按照特定的顺序操作集合,而java也专门提供了Collections工具来对集合进行操作。下面来看看几个例子

List list = new ArrayList();

list.add("one");//此处省略 ,一共添加五个元素one,two,three,fore,five

Collections方法

Collection.reverse(list);//反转集合元素的顺序

Collection.shuffle(list);//随机顺序,多次随机结果可能不一样

Collection.sort(list);//升序排序,先数字后字母,数字0-9,字母A-Z a-z的顺序,逐位比较

Collection.swap(list,0,3);//交换第一个和第四个元素位置

看一个swap的源码实现

Object tmp = arr[i];

arr[i] = arr[j];

arr[j] = temp;

嗯,完了,是不是有一种这玩意我都会写,干嘛要用这个的感觉?其实确实可以自己写,但是一般提供工具给别人用,肯定要提供全套,再就是合理的使用工具会减少不必要的代码,提升代码的可读性。

Collection 和 Collections

这两个长得很像,但是作用差别很大,初学者切勿将两者概念混淆。Collection是集合体系中的上层接口,而Collections是操作集合的工具。何谓工具?还记不记得我们讲的静态方法?不记得的快去复习类和对象的文章。

Collections作为一个工具类,里面提供的方法都是静态方法,所以在上面的例子中,都是直接使用类Collections来调用方法,Collections提供了大量的静态方法来操作集合,有没有加深对静态成员这个概念的理解?

用Collections工具类创建线程安全的集合

上次讲vector的时候,说了他是线程安全的集合,而List是线程不安全的。但是可以通过一些方法让List变成线程安全的,所以vector目前已经没有使用的必要了。那么如何让List变成线程安全的集合呢?答案就是使用Collections工具可以将List变为线程安全。

Collections有一系列的synchronized方法来使集合变为线程安全的,一系列是指不仅仅可以将List变为线程安全的,Set,Map也有方法变成线程安全的。

List list = Collections.synchronizedList(new ArrayList());

Set set = Collections.synchronizedSet(new HashSet());

Map map = Collections.synchronizedMap(new HashMap());

使用以上三个工具方法就可以将普通集合变为线程安全的集合。这些方法有什么魔法么,为什么外面包一层就线程安全了?下面来简单介绍一下多线程以及使用多线程会遇到的问题。

多线程是什么?

多线程就是并行处理问题。比如去银行取钱,如果只有一个取款机队伍就会排很长,但是如果有多个取款机同时办理业务,速度就会快很多。这就是多线程的思路,多个线程(取款机)处理一个问题(取钱)。

多个ATM

为什么多线程有安全问题?

假设现在有2个人要取款,如果2个人同时操作一个取款机会发生什么?第一个人密码输了3位数,第二个人跑来按3位数,第一个人删了准备重新输,又被第二个人按了3下,这样下去两个人都别想取钱。多个线程抢同一个资源就会产生线程安全问题,实际开发中遇到的线程安全问题会比这种情况还要复杂。

怎么解决?

带锁的ATM

新款取款机,带门带锁的!一旦一个人进去了,先锁门,然后就可以放心大胆的取钱了,这时候没有人会来跟你抢着取钱了。代码里面也是可以上锁的,所以线程安全的集合都是带有锁机制的。

高效并发容器

这里是补充知识,了解即可。其实上面的这几个方法确实可以将普通集合转为线程安全的集合,但是实现很粗糙,导致效率不是很高。所以就有了专门为并发情况设计的更加高效的并发容器,比如CopyOnWriteArrayList,CopyOnWriteArraySet,ConcurrentHashMap。

上锁也是有很多种上锁的方法,继续取钱的例子。

最极端粗暴的上锁方式就是,银行每次只准进一个人,这样绝对不会有任何问题,绝对安全,银行所有保安都盯着你,你还能玩出花来?但是这样做效率极端底下。比如老版本的vector和hashtable就是用类似这种粗暴的方法来上锁。

再来看稍微先进点的上锁方式。就是银行可以进很多人,但是办理不同业务的分开来,取钱的一个队,存钱的一个队,办理财换密码再来一个队,每个队同时只能一个人办,办的人进小房间,上锁。这种上锁的粒度比上面那种要小,效率要快很多。

最后就是最先进的锁了。也就是类似并发容器这种,升级版的取款机不仅可以取钱还可以存钱,还能办其他业务~也就是说不管办什么业务,找个人最少的队排着就行了,所有机器可以同时办相同或者不同的业务。这种锁的粒度最小,只对操作对象的数据进行上锁,效率最高。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-12-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码思客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档