首页 >> 大全

16.整理华为面经--1

2023-07-28 大全 39 作者:考证青年

java常用集合及其特点

Java提供的众多集合类由两大接口衍生而来:接口和Map接口,以下只列出了常用的实现类

接口定义了一个包含一批对象的集合。接口的主要方法包括:

Map接口在的基础上,为其中的每个对象指定了一个key,并使用Entry保存每个key-value对,以实现通过key快速定位到对象(value)。Map接口的主要方法包括:

对于List接口:

基于数组来实现集合的功能,其内部维护了一个可变长度的数组对象(数组默认长度为10,每次扩容默认为1.5倍原来的容量)

基于双向链表来实现集合的功能,每个Node都拥有前一个Node和后一个的引用,要注意的是它的get方法会遍历整个链表,所以不要使用get方法遍历元素,应该使用接口

是一个线程安全的但是他是通过加锁实现的,效率低,但是他的好处是可以定义数组长度的扩容因子,现在基本没人用了

是的线程安全版本,与不同,它通过写时复制的操作来解决线程安全问题,在写的时候,它会先复制出一个副本,在新副本上进行写的操作,然后再修改引用,只能保证数据的最终一致性,并不能保证实时一致性,并且它会占用更多的内存空间.

注意点:

写时复制不会修改原来的容器,只修改副本容器,所以可以对原始的容器进行并发的读,实现了读写分离,读的操作发生在原始容器上,写的操作发生在副本容器上

读操作的线程可能不会立即读取到新修改的数据,因为修改操作发生在副本上,但是最终修改操作会完成并且更新容器,因此这是最终一致性,因此它不适用与实时读的场景

COWA的add操作都是在锁的保护下进行的,这样做事为了避免在多线程并发add的时候复制出多个副本,而读的操作是不需要加锁的,因此它适用于读多写少的场景

对于Set接口:

Set 接口继承,用于存储不含重复元素的集合。几乎所有的Set实现都是基于同类型Map的,简单地说,Set是阉割版的Map。每一个Set内都有一个同类型的Map实例(除外,它内置的是实例),Set把元素作为key存储在自己的Map实例中,value则是一个空的。Set的常用实现也包括 、、t等,原理和对应的Map实现完全一致。

对于Map接口:

:底层结构jdk1.8以前是使用数组+链表来实现的,jdk1.8以后是采用数组+链表+红黑树实现,在链表长度阈值超过8的时候,链表将转化为红黑树,小于6的时候又转回来,此外它是线程不安全的,支持null值为key,而且会把这个key放在数组的0号位置,的基础容量为16,默认的填充因子为0.75,其扩容时默认翻倍即(2*16*0.75).多线程情况下使用.()可以得到一个线程安全的

:(已经很少使用)线程安全版本的,加锁来实现线程同步,不允许null值作为key,初始容量为11,负载因子为0.75,默认扩容时*2+1

:的线程安全版本,使用分离锁和等方法极大地提升了读写性能,同时也能保证在绝大部分情况下的数据一致性。但其不能保证绝对的数据一致性, 在一个线程向Map中加入Entry的操作没有完全完成之前,其他线程有可能读不到新加入的Entry

注意点:

jdk1.7以前本质上还是采用链表+数组的形式存储键值对的。但是,为了提高并发,把原来的整个 table 划分为 n 个 。所以,从整体来看,它是一个由 组成的数组。然后,每个 里边是由 组成的数组,每个 之间又可以形成链表。我们可以把每个 看成是一个小的 ,其内部结构和 是一模一样的。

jdk1.8采用CAS+

jdk1.8中取消了分段式锁的封装,存储结构和数据操作原理与普通一样,数组+[链表|树]。其保证线程安全的核心思想是,插入元素时如果没有冲突,也就是说index处为空,则执行CAS插入操作;如果index处已经有元素了,则使用锁定index处元素,再进行插入操作。

:和非常类似,但它在Enrty的基础上增加了两个用于前插和后插的引用,来实现能够按照Enrty的插入顺序进行遍历

:基于红黑树实现的Map结构,Enrty拥有左右叶子结点和父节点的引用,同时还记录了自己的颜色,的Entry是有序的,所以提供了一系列方便的功能,比如获取以升序或降序排列的()、获取在指定key(Entry)之前/之后的key(Entry)等等

对于Queue/Deque接口:

Queue和Deque接口继承接口,实现FIFO(先进先出)的集合。二者的区别在于,Queue只能在队尾入队,队头出队,而Deque接口则在队头和队尾都可以执行出/入队操作

Queue接口常用方法:

Deque接口常用方法:

e是基于链表实现的队列,队列中每个Node拥有到下一个Node的引用:由于Node类的成员都是的,所以e自然是线程安全的。能够保证入队和出队操作的原子性和一致性,但在遍历和size()操作时只能保证数据的弱一致性。

是一种无界的阻塞队列。所谓阻塞队列,就是在入队时如果队列已满,线程会被阻塞,直到队列有空间供入队再返回;同时在出队时,如果队列已空,线程也会被阻塞,直到队列中有元素供出队时再返回。同样基于链表实现,其出队和入队操作都会使用进行加锁。所以本身是线程安全的,但同样的,只能保证入队和出队操作的原子性和一致性,在遍历时只能保证数据的弱一致性。

是一种有界的阻塞队列,基于数组实现。其同步阻塞机制的实现与基本一致,区别仅在于前者的生产和消费使用同一个锁,后者的生产和消费使用分离的两个锁。

不能保存任何元素,size永远是0,peek()永远返回null。向其中插入元素的线程会阻塞,直到有另一个线程将这个元素取走,反之从其中取元素的线程也会阻塞,直到有另一个线程插入元素。这种实现机制非常适合传递性的场景。也就是说如果生产者线程需要及时确认到自己生产的任务已经被消费者线程取走后才能执行后续逻辑的场景下,适合使用

开启一个线程的方法

继承类,继承后重写run方法,调用对象的start方法开启线程

华为界面整理_华为手机卓面整理_

实现接口,实现run方法,将此对象放在类构造器中,创建类对象然后调用start方法

线程池+方法

如何保证线程安全

关键字

CAS+

final关键字

修饰类表示类不可被继承,修饰方法表示方法不能被重写 ,修饰变量表示变量不可被更改

值得注意的一点是局部内部类和匿名内部类访问局部变量必须加上final关键字

内部类和外部类是处于同一个级别的,内部类不会因为定义在方法中就随着方法的执行完毕而销毁,当外部类的方法结束了,局部变量就被销毁了,但是内部类对象还是存在的(稍后GC再进行回收),这时内部类对象访问了一个不存在的变量,为了解决这个问题就将局部变量复制了一份作为内部类的成员变量,这样当局部变量死亡之后,内部类依然可以访问它,实际访问的是局部变量的copy,这样就延长了局部变量的生命周期

将局部变量复制为内部类的成员变量的时候,必须保证这两个变量时一样的,也就是我们在内部类中修改了成员变量,方法中的局部变量也得跟着改,所以就将局部变量设置为final,对他初始化后就不让你去修改这个变量,这就保证了两个变量的一致性,这实际上也是一种妥协.

的模板和特点?

的核心是ioc(控制反转)+aop(面向切面编程)

常用的设计模式?--见设计模式专栏

redis的特点

redis是一种键值数据库但是他在保持键值数据库简单快捷的特点的同时又吸收了部分关系数据库的优点,它不仅保存类型的数据,还能保存Lists类型(有序)和Sets类型(无序)的数据,而且还能完成排序(SORT) 等高级功能,在实现INCR,SETNX等功能的时候,保证了其操作的原子性,除此以外,还支持主从复制等功能.

速度快-->使用标准C写,所有数据都在内存中完成,读写速度分别达到10万/20万

持久化-->采用写时复制的技术,可以异步的保存在磁盘上,RDB+AOF

支持事务-->但是不保证原子性,redis中的一个事务中如果存在命令执行失败,那么其他命令依然会被执行,没有回滚机制

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了