每日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、同步和阻塞有什么关系?
- 同步与阻塞同步是个过程
- 阻塞是线程的一种状态。
- 多个线程操作共享变量时可能会出现竞争。
- 这时需要同步来防止两个以上的线程同时进入临界区
- 在这个过程中,后进入临界区的线程将阻塞,等待先进入的线程走出临界区。