集合,线程知识点总结

java集合

为什么集合只能存放引用数据类型?

java集合实际存放的是对象的引用,每个集合元素都是一个引用变量,实际内容都存放在堆内存或方法区中,但是基本数据类型是在栈内存上分配空间的,栈上的数据会随时被收回的

java中的常用的集合有几种?

(set,list,map)除了这几个常用的,还有一个queue(队列), 并且set,list,queue的同一个父类是collection,map和collectin是同一级,但是没有什么联系,是相互独立的。

Set集合:集合元素是不能重复的。元素是没有顺序的。所以它不能基于位置访问元素。TreeSet和HashSet是它的实现类。

List集合: 集合元素是可以重复的。元素是有顺序的。所以它可以基于位置访问元素。ArrayList和LinkedList是它的实现类。

Map:它包含键值对。Map的键是不能重复的。Map不能保证存储的顺序。HashMap和TreeMap是它的实现类。

Queue用于模拟队列这种数据结构。

集合的数据结构

(1)Set接口是collection的子接口:

 HashSet 其底层是由哈希表(其实还是数组和单链表实现)实现,hashset的底层是基于hashMap来实现的。Hash可以存入null值,但是只能存储一个null。

HashSet遍历的三种方法:foreach遍历,使用数组遍历,使用迭代器

LinkedHashSet 底层实现:继承hashset类,基于LinkedHashMap来实现的,和hashSet的区别主要在于它是双向链表结构,有顺序。在插入元素的时候,也是通过元素的哈希值来进行来决定元素的存储位置。但是利用链表的来保证以插入的顺序来进行保存元素

TreeSet 底层实现是通过treeMap(二叉树)实现的,是一个有序集合类,存入Treeset集合的值,并不是按照插入顺序来排序。排序的实现有两种:

自然排序:实现comparable要使用要排序的元素的compareTo(object obj)方法进行比较元素之间的大小关系,然后将元素进行升序排列。

定制排序:如果要定制排序,就要实现comparator接口,实现int compare方法

(2)List接口是collection的子接口:

ArrayList 数据结构:底层实现是object数组(动态数组,可以扩容),它的随机访问速度极快,但是插入和删除的操作需要移动数组中的元素,比较麻烦。

注意:1)它在没有初始化长度的时候,默认长度是10

2)如果向ArrayLIst添加元素,超过了原来的容量,那么扩容方案:扩容到原数组的1.5倍,如果扩容完之后还是小于返回到mincapacity(最小容量)

3)ArrayList是线程不安全的,在多线程的情况下不要使用

如果非要使用list,就推荐使用vector,它基本上和ArrayList一样,区别在于vector中大部分方法都使用了同步关键字synchronized修饰,这样在多线程不会出现并发错误,扩容区别vector默认扩容就是原来的2倍。

ArrayList遍历的几种方式:1:使用foreach遍历list 2:将list转化为数组,在进行遍历使用迭代器遍历

LinkedList 数据结构:双向链表 随机访问速度慢,查找元素是从头开始一个一个查找,但是适合于频繁的插入和删除操作。线程不安全

LinkedList内部实现原理:LinkedList内部有一个类似于C语言的1结构体的Entry内部类,它包含了前一个元素的地址引用和后一个元素的地址引用,类似C语言的指针。进行操作元素。

(3)Map集合:

HashMap 基于哈希表的map接口实现,底层使用数组和单链表实现。使用了哈希算法,以便进行快速查询,线程不安全,存入的顺序和遍历的顺序可能不一致。

LinkedHashMap是map接口的哈希表和链表来实现的。

TreeMap 底层实现是红黑树,可以用于排序。排序分为两种:TreeMap提供了四个构造方法,实现了方法的重载。无参构造方法中比较器的值为null,采用的是自然排序的方法,如果指定了比较器则是定制排序。

集合是否线程安全的总结:

线程安全:Vector,HashTable(jdk1.0引入),

线程不安全:ArrayList,LinkedList,HashMap,TreeMap,TreeSet,HashSet

HashTable和hashMap之间的区别:

1. HashMap几乎可以等价于Hashtable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受为null的键值(key)和值(value),而Hashtable则不行)。

2.HashMap是非synchronized,而Hashtable是synchronized,这意味着Hashtable是线程安全的,多个线程可以共享一个Hashtable;而如果没有正确的同步的话,多个线程是不能共享HashMap的。Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。

3. 由于Hashtable是线程安全的也是synchronized,所以在单线程环境下它比HashMap要慢。如果你不需要同步,只需要单一线程,那么使用HashMap性能要好过Hashtable。

HashSet和HashMap区别:

1、HashSet底层是采用HashMap实现的。HashSet 的实现比较简单,HashSet 的绝大部分方法都是通过调用 HashMap 的方法来实现的,因此 HashSet 和 HashMap 两个集合在实现本质上是相同的。

2、HashMap的key就是放进HashSet中对象,value是Object类型的。

3、当调用HashSet的add方法时,实际上是向HashMap中增加了一行(key-value对),该行的key就是向HashSet增加的那个对象,该行的value就是一个Object类型的常量

TreeSet和TreeMap区别:

1. 最主要的区别就是TreeSet和TreeMap分别实现Set和Map接口

2.TreeSet只存储一个对象,而TreeMap存储两个对象Key和Value(仅仅key对象有序)

3.TreeSet中不能有重复对象,而TreeMap中可以重复

4.TreeMap的底层采用红黑树的实现,完成数据有序的插入,排序。因此它要求一定要有Key比较的方法,要么传入Comparator实现,要么key对象实现Comparable接口。

线程安全问题

线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。

线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。

hashmap为什么线程不安全?

第一:如果多线程同时使用put方法添加元素,如果两个线程添加数据的位置是一个位置,那么最终第二个线程添加的数据会把第一个线程添加的数据覆盖

第二:扩容时引起死循环。当两个线程同时检测到元素个数超过阀值,此时两个线程都会调用resize()方法进行扩容,两个线程同时修改一个链表结构会产生一个循环链表。接下来,在想通过get()获取某一个元素,就会出现死循环。

使hashmap线程安全?

方法一:通过Collections.synchronizedMap()返回一个新的Map,这个新的map就是线程安全的,Collections.synchronizedMap()封装所有不安全的HashMap的方法,就连toString, hashCode都进行了封装. 封装的关键点有2处,1)使用了经典的synchronized来进行互斥, 2)使用了代理模式new了一个新的类,这个类同样实现了Map接口.

方法二:重新改写了HashMap,具体的可以查看java.util.concurrent.ConcurrentHashMap.

使用了新的锁机制(可以理解为乐观锁)

把HashMap进行了拆分,拆分成了多个独立的块,这样在高并发的情况下减少了锁冲突的可能

ConcurrentHashMap的锁分段技术

concurrenthashmap容器里有多把锁,每一把锁用于锁住容器中的一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据时,其他段的数据也能被其他线程访问。

什么实用concurentHashMap技术?

concurrentHashmap是支持完整的并发操作和更新,当有大量的并发和更新时,我们可以使用

hashtable为什么是线程安全的?

HashTable容器使用synchronized来保证线程安全,但在线程竞争激烈的情况下,HashTable的效率非常低下。因为当一个线程访问HashTable的同步方法时,其他线程访问HashTable的同步方法时,可能会进入阻塞或轮询状态。如线程1使用put进行添加元素,线程2不但不能使用put方法添加元素,并且也不能使用get方法来获取元素,所以竞争越激烈效率越低。

hashset线程不安全?

Set的特点就是存放的数据不会重复。因为它的内部会首先读内部保存的数据,是否存在,如果存在就不存放进去,否则存放进去。也就是说数据的存入操作是分两步,首先读取,然后写入。假设不是线程安全,那很可能出现的一种情形就是当线程A判断该set对象没有某个元素,正准备将该元素插入之前,线程B也判断该对象不存在该元素,也准备插入,最后的结果导致了两个相同的元素被插入了。

ArrayList为什么线程不安全

1、出现数组越界问题

当列表大小为9,size=9,线程A开始进入add方法,此时获取size=9进行是否需要扩容判断,线程B此时也进入add方法,它获取到的size也是9,进行扩容判断。线程A判断之后,不需要扩容,开始设置值操作,elementdata[size++]=e,结果size=10。线程B判断之后,也不需要扩容,进行设置值操作elementdata[size++]=e,但是此时就会出现数组越界异常(数组默认0-9),elementdata[10]超出范围,所以线程不安全

2、多线程环境下执行时,可能就会发生一个线程的值覆盖另一个线程添加的值

列表大小为0,即size=0

线程A开始添加一个元素,值为A。此时它执行第一条操作,将A放在了elementData下标为0的位置上。

接着线程B刚好也要开始添加一个值为B的元素,且走到了第一步操作。此时线程B获取到size的值依然为0,于是它将B也放在了elementData下标为0的位置上。

线程A开始将size的值增加为1

线程B开始将size的值增加为2

解决ArrayList线程不安全

一:使用synchronized关键字,这个大家应该都很熟悉了,不解释了;

二:使用Collections.synchronizedList();使用方法如下:

   假如你创建的代码如下:List<Map<String,Object>> data=new ArrayList<Map<String,Object>>();

        那么为了解决这个线程安全问题你可以这么使用Collections.synchronizedList(),如:

        List<Map<String,Object>> data=Collections.synchronizedList(new ArrayList<Map<String,Object>>());


LInkedList线程安全问题解决?

1、List<String> list = Collections.synchronizedList(new LinkedList<String>());

  2、LinkedList换成ConcurrentLinkedQueue

hashmap是如何工作的?

HashMap是一个针对数据结构的键值,每个键都会有相应的值,关键是识别这样的值。

HashMap 基于 hashing原理,我们通过 put ()和 get ()方法储存和获取对象。当我们将键值对传递给 put ()方法时,它调用键对象的 hashCode()方法来计算 hashcode,然后找到bucket 位置来储存

值对象。当获取对象时,通过键对象的equals ()方法找到正确的键值对,然后返回值对象。HashMap 使用 LinkedList(链表) 来解决碰撞问题,当发生碰撞了,对象将会储存在 LinkedList (链表)的下一个节点中。 HashMap 在每个 LinkedList(链表) 节点中储存键值对对象。

判断hashset中是否是重复的对象?

先判断两个对象的hashcode是否相同(如果两个对象的hashcode相同,不一定是一个对象,如果两个对象的hashcode不同,一定不是一个对象)如果两个hashcode相同,在进行equals方法判断,如果equals相同则是同一个对象,如果equals判断不相同,那么就不是一个对象。

hashset存储原理?

1、将要传入的数据根据系统的hash算法得到一个hash值

2、根据hash值计算出数据在hash表中的位置

3、判断该位置是否有值,没有值就将数据插入进来,如果有值则再次判断传入的值与已经存储的值的equals结果是否相同,如果相同则不存,如果不相同则通过单链表的形式存储


Arraylist添加元素的原理?

1、调用add方法,在插入数据之前,先要判断数组是否能够再容下元素(调用方法参数是size+1,是当前数组长度+1也就是mincapacity最小容量),此时要判断是默认数组还是自定义数组。如果是默认数组先判断mincapacity和默认数组长度10谁大,返回谁。如果是自定义的数组,直接返回mincapacity。根据返回的值和数组的定义长度大小比较,如果返回的值大,则进行扩容。

2、扩容:根据传入的mincapacity和数组的容量长度对比,如果mincapacity大于数组长度,需要扩容。先根据原来的数组的长度,进行扩容到原来数组长度的1.5倍。如果扩容之后的容量小于mincapacity,则将mincapacity赋值给新数组的容量。如果扩容之后的容量大于数组定义最大容量,那么赋值给新数组Integer.MAX_VALUE-8

3、调用copyof方法,新建了一个数组,将原数组的对象复制到新的数组中,并且将现有的数组指向新的数组。

4、在调用element[size++]=e添加元素。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容