每日Android面试题
1、HashMap与TreeMap、HashTable的区别及适用场景?
-
HashMap: 非线程安全
-
HashMap:基于哈希表(散列表)实现。
-
使用HashMap要求添加的键类明确定义了hashCode()和equals()
-
[可以重写hashCode()和equals()]
-
为了优化HashMap空间的使用,可以调优初始容量和负载因子。
-
其中散列表的冲突处理主要分两种,
-
一种是开放定址法,另一种是链表法。HashMap的实现中采用的是链表法。
-
TreeMap:非线程安全基于红黑树实现。TreeMap没有调优选项,因为该树总处于平衡状态。
-
适用场景分析:
-
HashMap和HashTable:HashMap去掉了HashTable的contains方法
-
但是加上了containsValue()和containsKey()方法
-
HashTable同步的,而HashMap是非同步的,效率上比HashTable要高。
-
HashMap允许空键值,而HashTable不允许。
-
HashMap:适用于Map中插入、删除和定位元素。
-
Treemap:适用于按自然顺序或自定义顺序遍历键(key)。
2、concurrentHashmap原理,原子类?
-
ConcurrentHashMap作为一种线程安全且高效的哈希表的解决方案尤其其中的"分段锁"的方
-
相比HashTable的全表锁在性能上的提升非常之大.
-
ConcurrentHashMap 有 16 个 Segments
-
所以理论上,这个时候,最多可以同时支持 16 个线程并发写
-
只要它们的操作分别分布在不同的 Segment 上
-
这个值可以在初始化的时候设置为其他值,但是一旦初始化以后,它是不可以扩容的。
-
再具体到每个 Segment 内部,其实每个 Segment 很像之前介绍的 HashMap,不过它要保证线程安全,所以处理起来要麻烦些。
-
initialCapacity:初始容量,这个值指的是整个 ConcurrentHashMap 的初始容量,实际操作的时候需要平均分给每个 Segment。
-
loadFactor:负载因子,之前我们说了,Segment 数组不可以扩容,所以这个负载因子是给每个 Segment 内部使用的。
-
Segment 内部是由 数组+链表 组成的。
3、HashSet与Treeset的适用场景?
-
TreeSet 是二叉树(红黑树的树据结构)实现的
-
Treeset中的数据是自动排好序的,不允许放入null值。
-
HashSet 是哈希表实现的,HashSet中的数据是无序的
-
可以放入null,但只能放入一个null,两者中的值都不能重复,就如数据库中唯一约束。
-
HashSet要求放入的对象必须实现HashCode()方法
-
放入的对象,是以hashcode码作为标识的
-
而具有相同内容的String对象,hashcode是一样,所以放入的内容不能重复
-
但是同一个类的对象可以放入不同的实例。
-
适用场景分析:
① HashSet是基于Hash算法实现的,其性能通常都优于TreeSet。
② 为快速查找而设计的Set,我们通常都应该使用HashSet
③ 在我们需要排序的功能时,我们才使用TreeSet。
多线程
1、什么是并发什么是并行
-
并行:多个cpu实例或者多台机器同时执行一段处理逻辑
-
并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。
-
并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈
-
我们会用TPS或者QPS来反应这个系统的处理能力。
-
Android针对并发一般都是采用静态页面的策略
2、什么是线程安全
-
线程安全:在并发的情况之下,该代码经过多线程使用,线程的调度顺序不影响任何结果。
-
这个时候使用多线程,我们只需要关注系统的内存,cpu是不是够用即可。
-
线程不安全:反过来,线程不安全就意味着线程的调度顺序会影响最终结果
3、什么是同步异步?
-
同步:就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回
-
要想实现同步操作,必须要获得线程的对象锁。
-
获得它可以保证在同一时刻只有一个线能够进入临界区,并且在这个锁被释放之前,其他的线程都不能再进入这个临界区。
-
如果其他线程想要获得这个对象的锁,只能进入等待队列等待。
只有当拥有该对象锁的线程退出临界区时,锁才会被释放,等待队列中优先级最高的线程才能获得该锁。 -
实现同步的方式有两种:同步方法、同步代码块。
-
异步:当一个异步过程调用发出后,调用者不会立刻得到结果。
-
实际处理这个吊用的部件是在调用发出后,通过状态、通知来通知调用者,或通过回调函数处理这个调用。
-
由于每个线程都包含了运行时自身所需要的数据或方法,
-
因此,在进行输入输出时,不必关系其他线程的状态或行为,也不必等到输入输出处理完毕才返回。
-
当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,异步能够提高程序的效率。
4、什么是线程阻塞?
-
阻塞:阻塞调用是指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。
-
非阻塞:指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。
5、同步和阻塞有什么关系?
-
同步与阻塞同步是个过程
-
阻塞是线程的一种状态。
-
多个线程操作共享变量时可能会出现竞争。
-
这时需要同步来防止两个以上的线程同时进入临界区
-
在这个过程中,后进入临界区的线程将阻塞,等待先进入的线程走出临界区。