blog中的图片有些事转载自其他大神,目前想找Android方面的工作,所以,会不定时的跟新我自己整理的知识点。大家多多交流,如有问题,请大家批评指正
- Android组件和线程框架
1、进程和线程
- 地址空间和其他资源:进程间相互独立,进程中包括多个线程,线程间共享进程资源某进程内的线程在其他进程内不可见
- 通信:进程间通信通过IPC机制,线程间通信通过数据段(如:全局变量)的读写,需要进程同步和互斥手段的辅助,以保证数据的一致性
- 调度和切换:进程是资源分配单位,线程是cpu调度单位,跟cpu真正打交道的是线程,线程上下文切换比进程上下文切换要快得多
2、内存溢出和内存泄漏
- 内存溢出:指程序在申请内存时,没有足够的空间供其使用
- 内存泄漏:指程序分配出去的内存不再使用,无法进行回收
3.GC简述当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象,通过这种方式确定哪些对象是”可达的”,哪些对象是”不可达的”。当GC确定一些对象为”不可达”时,GC就有责任回收这些内存空间。但是,为了保证 GC能够在不同平台实现的问题,Java规范对GC的很多行为都没有进行严格的规定
11、Java中4种引用类型
StrongReference(强引用):从不回收,对象一直存在,当JVM停止的时候才被终止,宁可抛异常OOM使程序终止,也不回收它。 Object obj=new Object();
SoftReference(软引用): 实现内存敏感的高速缓存,可以和引用队列(ReferenceQueue)联合使用,当内存不足时被终止,,回收后这个软引用会加入到与之关联的引用队列中,内存足够,不回收,OOM问题
WeakReference(弱引用):一旦发现,就会被回收, 但垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些具有弱引用的对象。可以和引用队列(ReferenceQueue)联合使用,当内存不足时,触发GC后被终止 内存泄漏
PhantomReference(虚引用): 主要用于跟踪对象垃圾回收器回收的活动。就是在对象被收集器回收时收到一个对象实例。必须和引用队列(ReferenceQueue)联合使用,随时会被回收,触发GC后被终止
SoftReference和WeakReference的区别:
WeakReference的生命周期比SoftReference的生命周期短
SoftReference多用于图片的缓存,而WeakReference多用于内存泄漏的解决
WeakReference可以通过手动GC进行清除
12.String、StringBuffer和StringBuilder
1、可变性
String类是用字符数组保存字符串,即private final char value[],所以String对象不可变
StringBuffer类与StringBuilder类都是继承AbstractStringBuilder类,AbstractStringBuilder是用字符数组保存字符串,即char value[],所以StringBuffer与StringBuilder对象是可变的
2、线程安全性
String类对象不可变,所以理解为常量,线程安全
StringBuffer类对方法加了同步锁,线程安全
StringBuilder类对方法未加同步锁,线程不安全
3、性能
String类进行改变的时候,都会产生新的String对象,然后将指针指向新的String对象
StringBuffer进行改变的时候,都会复用自身对象,性能比String高
StringBuilder行改变的时候,都会复用自身对象,相比StringBuffer能获得10%~15%左右的性能提升,但是得承担多线程的不安全的风险
15.hashmap hashset hashtable
- HashMap是基于哈希表的Map接口的非同步实现
- HashMap中元素的key是唯一的、value值可重复
- HashMap允许使用null值和null键
- HashMap中的元素是无序的
HashMap底层就是一个数组结构,数组中的每一项又是一个链表,当新建一个 HashMap 的时候,就会初始化一个数组,我们可以查看HashMap源码,在构造函数中
从源代码中可以发现:
1.根据key的hashCode重新计算hash值,根据hash值得到这个元素在数组中的位置(即下标)
2.如果数组该位置上已经存放有其他元素,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾
3.如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上
简单地说,HashMap在底层将key-value当成一个整体进行处理,这个整体就是一个Entry对象。HashMap底层采用一个 Entry[]数组来保存所有的key-value,当需要存储一个Entry对象时,会根据 hash 算法来决定其在数组中的存储位置,在根据equals方法决定其在该数组位置上的链表中的存储位置;当需要取出一个Entry时,也会根据hash算法找到其在数组中的存储位置,再根据equals方法从该位置上的链表中取出该Entry
h& (length-1)运算等价于对 length 取模,也就是 h%length,但是 & 比 % 具有更高的效率。当数组长度为 2 的 n 次幂的时候,不同的 key 算得的 index 相同的几率较小,那么数据在数组上分布就比较均匀,也就是说碰撞的几率小,相对的,查询的时候就不用遍历某个位置上的链表,这样查询效率也就较高了
Map 迭代
Map map = new HashMap();
Iterator iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
Object key = entry.getKey();
Object val = entry.getValue();
}
16.Map 扩容的影响?
当多线程的情况下,可能产生条件竞争。当重新调整HashMap大小的时候,确实存在条件竞争,如果两个线程都发现HashMap需要重新调整大小了,它们会同时试着调整大小。在调整大小的过程中,存储在链表中的元素的次序会反过来,因为移动到新的数组位置的时候,HashMap并不会将元素放在LinkedList的尾部,而是放在头部,这是为了避免尾部遍历(tail traversing)。如果条件竞争发生了,那么就死循环了
17.HahSet是什么?
- HashSet是无序的
- HashSet将对象存储在key中,且不允许key重复(和hashmap区别)
- HashSet的Value是固定的
对于HashSet而言,它是基于HashMap实现的。HashSet底层采用HashMap来保存元素,所有放入HashSet中的集合元素实际上由HashMap的key来保存,而HashMap的value则存储了一个PRESENT,它是一个静态的Object对象,但如果向HashSet中添加一个已经存在的元素,新添加的集合元素不会覆盖原来已有的集合元素。Hashmap会返回原value值。
18.HashTable是什么
- HashTable是基于哈希表的Map接口的同步实现
- HashTable中元素的key是唯一的,value值可重复
- HashTable中元素的key和value不允许为null,如果遇到null,则返回NullPointerException
- HashTable中的元素是无序的
19.LinkedHashMap是什么
- LinkedHashMap是基于哈希表的Map接口的非同步实现
- LinkedHashMap是HashMap的子类
- LinkedHashMap是有序的
- LinkedHashMap中元素的key是唯一的、value值可重复
- LinkedHashMap允许null键和null值
LinkedHashMap底层使用哈希表与双向链表来保存所有元素,它维护着一个运行于所有条目的双向链表(如果学过双向链表的同学会更好的理解它的源代码),此链表定义了迭代顺序,该迭代顺序可以是插入顺序或者是访问顺序
按插入顺序的链表:在LinkedHashMap调用get方法后,输出的顺序和输入时的相同,这就是按插入顺序的链表,默认是按插入顺序排序
按访问顺序的链表:在LinkedHashMap调用get方法后,会将这次访问的元素移至链表尾部,不断访问可以形成按访问顺序排序的链表。简单的说,按最近最少访问的元素进行排序(类似LRU算法)
LinkedHashMap采用的hash算法和HashMap相同,但是它重新定义了数组中保存的元素Entry,该Entry除了保存当前对象的引用外,还保存了其上一个元素before和下一个元素after的引用,从而在哈希表的基础上又构成了双向链接列表
20.LinkedHashSet是什么
1.LinkedHashSet是非同步的
2.LinkedHashSet是有序的,分别是插入顺序和访问顺序,LinkedHashSet的有序性可参考LinkedHashMap的有序性,可以举一反三
3.LinkedHashSet继承于HashSet,内部基于LinkedHashMap实现的,也就是说LinkedHashSet和HashSet一样只存储一个值,LinkedHashSet和LinkedHashMap一样维护着一个运行于所有条目的双向链表
21.LinkedList是什么
- LinkedList基于链表的List接口的非同步实现
- LinkedList允许包括null在内的所有元素
- LinkedList是有序的
- LinkedList是fail-fast的
LinkedList实现了 List 接口、底层基于链表实现的,所以它的插入和删除操作比ArrayList更加高效,但链表的随机访问的效率要比ArrayList差
LinkedList继承自AbstractSequenceList抽象类,提供了List接口骨干性的实现以减少实现 List 接口的复杂度
LinkedList实现了Deque接口,定义了双端队列的操作,双端队列是一种具有队列和栈的性质的数据结构,双端队列中的元素可以从两端弹出,其限定插入和删除操作在表的两端进行
LinkedList实现了Cloneable接口,即覆盖了函数clone(),能被克隆
LinkedList实现了java.io.Serializable接口,意味着ArrayList支持序列化
同步:hashtable和concurrentHashMap
有序:Linked
Hashmap是基于哈希表的map的接口非同步实现
Hashtable是基于哈希表的map的接口同步实现
Hashset是基于hashmap实现
22.ConcurrentHashMap是什么
1.ConcurrentHashMap基于双数组和链表的Map接口的同步实现
2.ConcurrentHashMap中元素的key是唯一的、value值可重复
3.ConcurrentHashMap不允许使用null值和null键
4.ConcurrentHashMap是无序的
ConcurrentHashMap定位一个元素的过程需要进行两次Hash操作,第一次Hash定位到Segment,第二次Hash定位到元素所在的链表的头部,因此,这一种结构的带来的副作用是Hash的过程要比普通的HashMap要长,但是带来的好处是写操作的时候可以只对元素所在的Segment进行加锁即可,不会影响到其他的Segment。正是因为其内部的结构以及机制,ConcurrentHashMap在并发访问的性能上要比Hashtable和同步包装之后的HashMap的性能提高很多。在理想状态下,ConcurrentHashMap 可以支持 16 个线程执行并发写操作(如果并发级别设置为 16),及任意数量线程的读操作
23.ConcurrentHashMap 的高并发性主要来自于三个方面:
1.用分离锁实现多个线程间的更深层次的共享访问,减小了请求同一个锁的频率
2.用HashEntery对象的不变性来降低执行读操作的线程在遍历链表期间对加锁的需求
3.通过对同一个Volatile变量的写 / 读访问,协调不同线程间读 / 写操作的内存可见性