1.回答输出结果,为什么?
Integer i = new Integer(100); Integer j = new Integer(100); System.out.println(i == j); String a = "abc"; String b = "a" + "b" + "c"; System.out.println(a == b); String c = "abcd"; String d = a + "d"; System.out.println(c == d);1.i==j :输出false,原因:i和j对象虽然在常量池范围内,但都通过new关键字分配新内存地址。
2.a==b:输出true,原因:都是字符串常量,都直接在字符串常量池中直接引用。
3.c==d:输出false,原因:d是在堆内创建新字符串对象。
2.String b在JVM中具体是怎么创建的?
在栈中创建一个b变量,在字符串常量池招是否存在“abc“,若找到了则直接引用,没有找到在字符串常量池中创建。
3.JVM中运行时数据区都包含那些部分?
分为线程私有和线程共享,线程私有:程序计数器,本地方法栈,虚拟机栈。
线程共享:元空间,堆,
4.堆是干嘛的?方法区是干嘛的?虚拟机栈是干嘛的?
堆:是用来存创建的对象,数组等,
方法区:存储字节码指令,类的结构信息,静态变量,常量,JIT编译器编译的目标对象识别的机器码。
虚拟机栈:存入一个个栈帧,一层层方法,每个栈帧保存了每个方法的局部变量,操作数栈和动态链接,方法出口等信息。
5.讲讲堆分为那些部分?每个部分都是啥?
堆分为新生代和老年代,新生代约占1/3分为survive0和survive1和Eden区,老年代约占2/3.
6.讲讲垃圾收集?
新生代中,对于Eden区域中的对象生命周期短,所以垃圾收集频率高,速率块,未回收的进入到survive0中,而在老年代中,对象占用空间大,生命周期长,回收频率低,速率慢。
7.一个对象是怎么从新生代流转到老年代的?
新生代对象经过频繁的垃圾收集还存活,达到阈值时会流转到老年代,当新生代容量不够时,survive0,survive1中的对象会直接流转为老年代对象。
8.surviveo区域、survive1区域,具体讲讲?
新生代中经历垃圾回收,存活的对象的年龄加1并放入到surivie0中,如果达到阈值,则流转为老年代对象。survive1和survive0中总有一个为空。
9.Java线程有那些状态,各个状态是怎么流转的
当线程新创建时,未执行start()方法时,处于New状态,当线程准备执行或正在执行时,处于RANNABLE状态,执行join(时间值),wait(时间值)等方法时间处于计时等待状态,等待时间结束处于RANABLE状态,执行join(),wait()方法时,处于等待状态,需要通过notify(),notifyall()等方法唤醒,如果存在锁,竞争锁失败的线程处于阻塞状态,执行ran()方法完毕,进入终止状态。
10.如果执行sleep方法会进入什么状态
线程会进入计时等待状态(休眠状态),如果有锁并不会释放锁,一直持有锁。
11.线程同步机制了解吗?
了解过,线程并发进行,线程采用抢占模式,为了使操作的资源正确,通过同步锁Synchronize保证线程的同步安全,也可以使用CAS和ReentrantLock保证线程同步安全。
12.Lock有哪些实现?
有ReentrantLock,ReentrantLockReadWriteLock等实现类,都是保证线程同步安全的
13.Synchronize和ReentrantLock有什么区别?分别在什么情况下使用?
Synchronize是一个关键字,声明在方法上或在代码块中使用,是隐式获取锁和释放锁,用法简单,不能中断,不能判断状态,不能设置超时,仅支持非公平锁,底层是通过Monitor监视器、
而ReentrantLock是Lock类的实现类,需要通过创建对象,通过对象调用获取锁和释放锁的方法,也可以trylock()非阻塞的方式,显式获取和释放锁,unlock()必须配合findlly 代码块使用,用法复杂,可以通过lockInterruptibly()中断,通过trylock(时间值)设置超时时间,支持公平锁和非公平锁,底层是通过AQS实现的。
14.讲讲Synchronize锁升级?
锁升级是从无锁->偏向锁->轻量级锁->重量级锁;
偏向锁是只有一个线程,频繁的获取释放锁,会记住这个线程,不用通过锁,直接比较实现,如果过发现不同的线程,会升级为轻量级锁,线程竞争不激烈,冲突小,线程通过CAS的方式获取锁,如果CAS长时间自旋,说明冲突激烈,锁会升级为重量级锁,具有强烈的互斥性和排他性,已独占的方式获取锁。
15.讲讲CAS的原理?会遇到什么问题?怎么解决?
CAS是一种无锁化的并发管理操作,执行流程是先获取内存中需要修改的值A,通过计算得出B,再将自己拿到的值A与内存中的值C比较,如果相同,则进行更新操作,如果不同,则进行重试,或自旋操作。
会出现ABA问题,是CAS拿到内存中的值A=10,但是存在另一个线程修改内存中的值为10,当前线程比较时,内存中的值与自己的值相同,边进行更新,没有发现其他修改的线程,可以通过加一个版本号解决。
16.线程安全的集合类有哪些?
1.CopyOnWriteArrayList,使用ReentrantLock保证线程安全。
2.CopyOnWriteArraySet,内部是一个CopyOnWriteArrayList,所以使用ReentrantLock保证线程安全。
3.ArrayBlockingQueue,使用一个锁ReentrantLock保证线程安全
4.LinkedBlockingQueue,使用两个锁对象(ReentrantLock)保证线程安全。
5.ConcurrentHashMap,使用CAS+synchronize保证线程安全,在没有发生哈希冲突时,使用CAS写入,发生发哈希冲突,使用链表头节点或红黑树的根节点作为锁对象进行局部上锁。
6.Stack,使用Synchronize保证线程安全。
17.如果我想要一个线程安全的List,应该怎么做?
可以使用CopyOnWriteArrayList,适合读多写少的场景
18.线程池了解嘛?有哪些核心参数?执行流程是什么?
线程池是一种池化技术,实现了线程复用,线程的并发管理,避免了线程的重复创建。
参数,核心线程数,最大线程数,非核心线程的空闲时间的时间单位,阻塞工作队列,线程工厂,拒绝策略。
执行流程:当线程任务进入线程池,判断小于核心线程数,则创建核心线程执行该线程任务,若大于核心线程数,小于工作队列,则线程任务入队等待,若大于工作队列小于最大线程数,创建非核心线程执行线程任务,若大于最大线程数,执行拒绝策略。
19.内存有限,快速找到top10000,怎么办?
使用优先队列(小顶堆栈)先遍历1000个数据通过for循环入队剩余元素,入队元素>队头元素,对头元素出队,遍历至数据结束,得到top10000
20. 数据量极大,找到一个数在其中是否存在,怎么做?
使用布隆过滤器,穿件创建布隆过滤器对象,把数据存入到布隆过滤器中,来判断某个数字是否存在
21.布隆过滤器的原理?优缺点?
将数据通过不同的哈希法计算出不同的哈希值,并在位数组中将计算出来的哈希值位置上的0改为1.
优点:可以高效率查询和插入数据,占用内存极小
缺点:存在误判,存入的数据不能取出原数据,原生布隆过滤器不支持删除。
22. 如果让你实现布隆过滤器的hash算法,怎么写?
使用不同的种子seed和容量cap和传如数据data
hash = seed*(cao-1)&(data.hashcode()^data.hashcode()>>>16)