JVM 配置
- 程序计数器:当前线程所执行的字节码的行号指示器
- java虚拟机栈:临时变量
- 元空间:类常量池,运行时常量池
- 方法区:类信息,静态变量
- 堆:对象实例,Sting常量池等
类加载过程
加载->链接(验证+准备+解析)->初始化->使用->卸载
加载:将硬盘中的二进制文件转为内存中的class对象
链接:给静态变量赋初始值,符号引用替换为直接引用
- 验证:检查载入的class 文件数据正确性。
- 准备:给类变量(静态变量)分配内存(方法区),直接赋值为最终值。
- 解析:将常量池内的符号引用替换为直接引用。
初始化:执行类变量(静态变量)的赋值和静态语句块
使用:若是第一次创建对象(对象所属的类没有加载到内存中),先执行初始化操作,再堆上为对象分配空间,所有属性设设置默认值,给实例变量赋值,初始化语句,检查是否有父类,有就先执行父类的构造函数。
GC垃圾回收流程
GC垃圾回收,是对堆内存的一清理。
堆内存:
年轻代:(eden[伊甸园],survior[存活区],vlrtual[伸缩区])
老年代:(tenured[旧生代],vlrtual[伸缩区])
永久代:(1.8后就不存在了,换为了元空间)
ArrayList是否线程安全?如何线程安全地操作ArrayList?
ArrayList 是线程不安全的,如果需要线程安全的List,可以从采用Vector/Collections.synchronizedList/CopyOnWriteArrayList
Vector: 使用synchronized关键字
Collections.synchronizedList: 内每一个方法都加了synchronized 关键字
CopyOnWriteArrayList: 在写操作的时候总是要复制,将原来的数据复制到新的数组进行操作,任何可变的操作都是通过ReentrantLock 控制并发。
线程不安全的原因:
当多个线程同时对一个数组进行操作时,如果线程1 执行 list[i] = “a” ,i++;线程2执行 list[i] = “b” ,i++;
如果线程同步执行了list[i] = 的操作,在执行i++,那么i+1 就有可能出现空值,list[i]的值同样可能出现被覆盖的情况。所以说ArrayList 线程不安全。
HashMap、TreeMap、LinkedHashMap的区别?
相同点:都是属于Map,都是通过K-V存储,K不允许重复。都是线程不安全的。
不同点:
项 | HashMap | TreeMap | LinkedHashMap |
---|---|---|---|
按顺序插入存放 | 不支持 | 不支持 | 支持,遍历时按插入的顺序输出 |
按Key排序 | 不支持 | 支持,默认按key升序 | 不支持 |
数据结构 | 数组+链表+红黑树 | 红黑树 | HashMap+双向链表 |
null | key,value都可以为空,但是Key只能有一个为空 | 不允许key,value为空 | key,value都可以为空,但是Key只能有一个为空 |
HashMap为什么线程不安全?如何线程安全地操作?
安全使用Map的三种方法:
1.HashTable,在get/put方法上加上了synchronized关键字,性能很差。
2.Collections.synchronizedMap,所有的方法都加上了synchronized关键字,性能很差。
3.ConcurrentHashMap,每次只给一个桶(数组项)加锁,性能好。
HashMap线程不安全的原因:
1.数据覆盖,
2.读出为null
3.JDK1.7会出现死循环。
ConcurrentHashMap原理?
在JDK1.8后,ConcurrentHashMap采用的是HashMap(数组+链表+红黑树)+synchronized +CAS的设计来实现线程安全。
CAS:在判断数组中当前位置为null时,使用CAS把这个新的节点写入对应数组中的位置。
synchronized:当数组中当前位置不为空时,通过加锁来添加这个节点进入数组(链表<8)或者红黑树(链表>=8)
线程池有哪些参数?
1.corePoolSize:线程池的核心线程数,即便没有任务也会有这么多的线程在等候;
2.maximunPoolSize:最大线程数,超过这个数量会触发拒绝策略。
3.keepAliveTime:线程存活时间,当线程大于corePoolSize时,等到这个时间还没有任务执行的话,线程退出。
4.unit:指定keepAliveTime的单位,如TimeUnit.SECONDS 秒。
5.workQueue:阻塞队列,提交的任务会被放在这个队列里。
6.threadFactory:线程工场,用来创建线程。
7.handler:拒绝策略