1. 为什么要有线程池,线程池的作用是什么
降低资源消耗
提高响应速度
提高线程的可管理性
2.Thread 的run和start的区别
调用start()方法可启动线程并使线程进入就绪状态,直接执行run()方法的话不会以多线程的方式执行
3.线程交替打印a和b
public class Main {
private static Lock lock=new ReentrantLock();
private static Condition A=lock.newCondition();
private static Condition B=lock.newCondition();
private static int count=0;
public void fun1(){
while(true) {
try {
lock.lock();
while (count != 0) {
A.await();
}
System.out.println("A");
count = 1;
B.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public void fun2(){
while(true){
try{
lock.lock();
while(count==0){
B.await();
}
System.out.println("B");
count=0;
A.signal();
}catch(Exception e){
e.printStackTrace();
}finally{
lock.unlock();
}
}
}
public static void main(String []args){
Main main=new Main();
new Thread(()->{
main.fun1();
}).start();
new Thread(()->{
main.fun2();
}).start();
}
}
4.java提供了那几个线程池预设模板
FixedThreadPool:固定线程数量的线程池,该线程池中的线程数量始终不变。当有一个新任务提交时,线程池中若有空闲线程,则立即执行。若没有,则新任务会被暂存在一个任务队列中,带有线程空闲时,便处理任务队列中的任务
SingleThreadExecutor:只有一个线程的线程池。若多余一个任务被提交到该线程池,任务会被保存在一个任务队列中,待线程空闲,按先入先出的顺序执行队列中的任务
CachedThreadPool:可根据实际情况实际调整线程数量的线程池。
ScheduledThreadPool: 给定的延迟后运行任务或者定期执行任务的线程池
5.线程池底层是什么,核心参数是什么
线程池的核心线程数量
线程池的最大线程数
当线程大于核心线程数时,多余的空闲线程存活的最长时间
时间单位
任务队列,用来存储等待执行任务的队列
线程工厂,用来创建线程
拒绝策略:提交任务过多不能及时处理,可以定制策略来处理任务
6.线程池中阻塞队列有哪几种
LinkedBlockedQueue有界阻塞队列,容量最大为Integer.MAX_VALUE
SynchronousQueue 同步队列,没有容量,不存储元素,目的是保证对于提交的任务,如果有空闲线程,则使用空闲线程来处理,否则新建一个线程来处理任务
DelayedWorkQueue延迟队列:内部元素并不是按照放入的时间排序,而是按照延迟的时间长短对任务进行排序,内部采用堆的数据结构,可以保证每次出队的任务都是当前队列中执行时间最靠前的
ArrayBlockingQueue:有界阻塞队列,底层由数组创建,容量一旦创建,就不能修改
7.JDK1.8新特性
Interface&functional Interface
Lambda
Stream
Optional
DateTime-api
8.hashmap get过程
计算哈希值,若数组元素相等,则直接返回。否则判断是否为树,如果是,则在树中查找,否则就在链表中查找。
9.mysql的事务隔离级别有哪些
读已提交 指的是一个事务还没提交时,他的变更就能被其他事务看到
读提交 指一个事务提交之后,他的变更才能被其他事务看到
可重复读 指的是一个事务执行过程中看到的数据,一直跟这个事务启动看到的数据是一致的
串行化 会对记录加上读写锁,在多个事务对这条记录进行读写操作时,如果发生读写冲突,后访问的事务必须等前一个事务执行完成,才能继续执行
10.说一说PriorityQueue
按照优先级最高的元素先出队
PriorityQueue利用二叉堆的数据结构来实现的,底层使用可变长的数组来存储数据
PriorityQueue通过堆元素的上浮和下沉,实现在O(logn)的时间复杂度来插入元素和删除堆顶元素
PriorityQueue是非线程安全的
PriorityQueue默认是小顶堆,但可以接收一个Comparator作为构造参数,从而来自定义元素的优先级
11.Redis的分布式锁
set lock_key unique_value nx px 10000
lock_key就是key键
unique_value是客户端生成的唯一的标识
nx代表只在lock_key不存在时,才对lock_key进行设置
px 10000表示设置lock_key的过期时间为10s,避免客户端发生异常而无法释放锁
12.Java内存模型
主内存(共享变量)
线程(本地内存含有共享变量副本)
13.聚簇索引和非聚簇索引区别
聚簇索引的叶子节点存放的是实际数据,所有完整的用户记录都存放在聚簇索引的叶子节点
非聚簇索引的叶子节点存放是主键值,而不是实际数据
14.B+树优势
B+树的非叶子节点不存放实际的记录数据,仅存放索引,因此数据量相同的情况下,相比存储即存储索引又记录的B树,B+树的非叶子节点可以存放更多的索引,因此B+树可以比B树更矮胖,查询底层节点的磁盘I/O次数会变少
B+树所有叶子节点间还有一个链表进行连接,这种设计对范围查询查找非常有帮助
15.NIO和BIO
BIO属于同步阻塞IO模型,应用程序发起read调用后,会一直阻塞,直到内核把数据拷贝到用户空间
NIO类似于IO多路复用模型,线程首先发起select调用,询问内核数据是否准备就绪,等内核把数据准备好哦啊,用户线程再发起read调用。Java中的NIO,有一个选择器,只需要一个线程便可以管理多个客户端,当客户端数据到了之后,才会为其服务
16.SPI机制
当接口存在于调用方这边时,就是SPI,由接口调用方确定接口规则,然后由不同的厂商去根据这个规则对这个接口进行实现,从而提供服务。
17.get和post区别
get是从服务器获取指定的资源
post是根据请求负荷对指定的资源作出处理
get方法是安全且幂等的,因为他是只读操作,而post是新增和提交数据的操作,会修改服务器资源,所以不是安全的,且多次提交就会创建多个资源,所以不是幂等的
18.equals和==区别
对于基本数据类型来说,==比较的是值
对于引用数据类型来说,==比较的是对象的内存地址
equals()不能用于判断基本数据类型的变量,只能判断两个对象是否相等
19.线程的生命周期和状态
new:初始状态,线程被创建出来但没有被调用start()
runnable状态:运行状态 线程被调用了start()等待运行的状态
blocked:阻塞状态 表示该线程需要等待其他线程作出一些特定动作通知或中断
time_wating:超时等待状态 可以在指定的时间后自行返回而不是像wating那样一直等待
terminated:终止状态 表示该线程已经运行完毕
20.mysql怎么解决幻读
快照读避免幻读:由MVCC多版本并发控制实现的,实现的方式是开始事务后,在执行第一个查询语句后,会创建一个Read View ,后续的查询语句利用这个ReadView,通过这个Read View就可以在undo log版本链找到事务开始时的数据,所以事务过程中每次查询的数据都是一样的。
当前读避免幻读:加上间隙锁来防止
参考资料:
GitHub - Snailclimb/JavaGuide: 「Java学习+面试指南」一份涵盖大部分 Java 程序员所需要掌握的核心知识。准备 Java 面试,首选 JavaGuide!