目录
- [1、说说Throw 和 Throws的区别](#1、说说Throw 和 Throws的区别)
- 2、构造方法能被重写吗
- 3、常见异常
- [4、Mysql中char 和 varChar区别](#4、Mysql中char 和 varChar区别)
- [5、Linux查看内存、查看某个应用相关进程 、查看当前所有tcp端口、查看文件被哪个进程占用](#5、Linux查看内存、查看某个应用相关进程 、查看当前所有tcp端口、查看文件被哪个进程占用)
- 6、利用链表实现LRU算法
- 7、Redis如何持久化到磁盘
- 8、谈谈mysql优化
- [9、jdk1.8 HashMap是如何实现的](#9、jdk1.8 HashMap是如何实现的)
- 10、聊聊java的反射
- 11、linux管道
- [12、git 常用命令:](#12、git 常用命令:)
- [13、merge rebase](#13、merge rebase)
- [14、tcp 四次挥手](#14、tcp 四次挥手)
- [15、https vs http](#15、https vs http)
- [16、tcp 为什么 可靠的?](#16、tcp 为什么 可靠的?)
- [17、死锁 如何避免?](#17、死锁 如何避免?)
- [18、 进程和线程的关系?](#18、 进程和线程的关系?)
- [19、 Java线程池](#19、 Java线程池)
- [20、 JVM垃圾回收算法?](#20、 JVM垃圾回收算法?)
- [21、 垃圾回收器?](#21、 垃圾回收器?)
- [22、 JVM 新生代 vs 老年代](#22、 JVM 新生代 vs 老年代)
- 23、为什么innodb不用哈希表、二叉树、红黑树
- 24、mysql和redis各自优势和缺点
- 25、linux发送一条指令到回显经历了什么过程
- 26、什么是进程同步,进程为什么要同步,同步的方法?
- 27、进程与程序的区别?
- 28、操作系统里的堆栈是什么?java里的堆栈是什么?
- 29、为什么要hashCode?
- 30、讲讲equals,讲讲hashMap的equals?
- 31、from区满了怎么办,强引用、软引用、弱引用。
- 32、垃圾回收机制为什么要分代?大对象和小对象的回收不同?
- 33、redis的内存淘汰机制?
- 34、close_time和wait_time的区别
- 35、Java的error和exception区别?
- 36、redis分布式锁?
- 37、mysql的默认隔离级别可重复读是怎么实现的
- 38、redis的数据结构
- 39、synchronized和ReenLock的区别
- [40、leftjoin 和rightjoin ,知道没用,要能说出来](#40、leftjoin 和rightjoin ,知道没用,要能说出来)
- 41、索引失效的场景
- 42、并发和并行的区别,java线程池中的线程之间是并发还是并行(根据cpu的核数)
1、说说Throw 和 Throws的区别
①throw定义在方法内,它是用来具体抛出某种类型;一般用在catch里面,程序执行到catch就会抛出throw定义的具体异常。
②throws定义在方法名后面,表示方法执行过程中可能会出现的异常,如果方法内某一处出现了异常,就会从这抛出。
两者抛出的异常都由它们的调用者来捕获
2、构造方法能被重写吗
不能,构造方法一般是用来创建对象并给对象初始化参数的。然后java中也不允许这样作
3、常见异常
空指针异常、数组越界异常、栈空间溢出异常、类找不到异常、文件未找到异常、运行时异常、IO异常
4、Mysql中char 和 varChar区别
char() 是括号内存储的长度是定长,如果char(10),此时存储一个字符串不超过10个字符,那么它内存占用10个;varchar()是变长,如果varchar(10),存一个字符串为5个字符,那么它内存就是5个字符
5、Linux查看内存、查看某个应用相关进程 、查看当前所有tcp端口、查看文件被哪个进程占用
查看内存:cat /proc/meminfo
查看java相关的进程 : ps -aux|grep java
查看当前所有tcp端口:netstat -ntlp
6、利用链表实现LRU算法
用双链表结构来记录元素,每当创建一个新元素时,如果即将超出规定容量,则把尾部元素移除。
如果没超除容量就不移除,每次调用一个元素时,都会把这个元素调到链表的头部;
7、Redis如何持久化到磁盘
①快照方式,简称RDB,会将某一时刻的内存数据,以二进制方式写入磁盘
②文件追加方式,简称AOF,记录所有操作命令,并以文本形式追加到文件中
可以通过save或bgsave命令手动持久化,前者会使redis进入阻塞状态;也可以在配置文件里改配置信息使其
自动持久化,比如每100s内有10个key值发生变化就自动持久化到磁盘。
8、谈谈mysql优化
9、jdk1.8 HashMap是如何实现的
首先他的底层是 数组+链表或红黑树的结构。
一、插入:当存入一个键时,会通过这个键计算出的hash值并将通过hash&(n-1)得到数组的索引位置(n为数
组长度) ,如果这个位置没有其他键,就会直接插入。如果有,就会先比较两者的hash值是否相等,不相等
的话就会在这个位置上以链式存储新来的键,如果两者hash值相等,就会拿新来的键的值替换掉原来的键的
值。
二、查找:查找也一样,先计算key的hash值,再计算出索引位置,再找到表上对应的结点,然后与结点及其
子结点进行比较 ,如果相等(这里相等可以是==或equals两者之一成立即可),则返回对应的结点值。
扩容机制:
①当HashMap的数组长度到达一个临界值的时候,就会触发扩容,把所有元素重新哈希之后再放在扩容后的
容器中,这是一个相当耗时的操作。而这个临界值就是由加载因子和当前容器的容量大小来确定的。
Ⅰ临界值=当前容器大小 * 加载因子(默认0.75)
Ⅱ为什么加载因子是0.75,因为有概率统计学的泊松分布有关,在加载因子为0.75时,key分布在hash表
Ⅲ里的位置可能更均匀把。
Ⅳ加载因子的作用:加载因子与哈希表大小结合,可使得哈希表以最大限度减小扩容操作,因为每次扩容
要重新计算哈希值,这是非常耗时的。
②当链表的长度大于8且数组长度超过64的话,链表就会转换成红黑树,当红黑树的结点个数少于
6的时候又会转回链表。
Ⅰ链表长度为什么是8,为什么不直接用红黑树?
因为链表的平均查找时间是8/2=4,红黑树的平均查找时间是3,如果长度是6或者7,两则查找时间
相差不大。为什么不直接用红黑树?因为红黑树一个结点要存储两个指针,而链表一个结点只要
存储一个指针,因此红黑树其实要比链表所占的空间大,基于空间与时间的权衡,因此才先使用链表,
后使用红黑树。
HashMap的初始化长度方式是懒汉式的,只有第一次put的时候才创建长度16的数组。
10、聊聊java的反射
java的反射,对于给定的任意一个类,都能通过反射的API获取到这个类的所有方法和属性信息。
对于任意运行时的一个对象,都能访问且调用调用它内部的方法和属性。比如给我一个类名就能调用它里面
的方法和属性,而不需要自己主动的new 对象。由于反射可以动态调用方法属性,所有能极大地发挥java的
灵活性。但是反射也有缺点,就是对性能有所损耗。
反射在java中有很多应用情景,比如在JDBC中用反射动态加载了数据库的驱动,动态生成代理类,注解。
11、linux管道
12、git 常用命令:
commit(提交到本地仓库)、push(提交到远程仓库)、clone(本地没有repository时,将远程repository整个下载过来)、pull(本地有repository时,将远程repository里新的commit数据(如有的话)下载过来,并且与本地代码merge)
13、merge rebase
①merge:将多个分支进行合并生成一个新的提交。每个分支上会继续保留各自的代码记录,主分支只保留提交记录。
②rebase:这个命令会始终把你最新的修改放到最前头。比如你对主分支进行rebase以后, 你的所有修改就会在主分支当前所有的修改之前。
14、tcp 四次挥手
time_wait
closed_wait 看计网文档
15、https vs http
①、http即超文本传输协议,它的信息是明文传输的,而且连接是无状态的。
②、https是由ssl加密传输协议+http协议构成的可以进行加密传输、身份认证的协议,前提是要到CA申请证书,一般要花费一些费用,它能大幅度防止数据传输过程中不被窃取和修改。但它也不是绝对安全的。由于加上了ssl的加密,ssl本身又综合使用了非对称加密和对称加密,所以https协议的握手阶段会更耗时,也会比http协议消耗额外多的资源。
16、tcp 为什么 可靠的?
①、tcp采用三次握手来建立可靠的连接
②、tcp使用校验和,确认(即发送ACK)和超时重传机制也保证了数据的可靠传输
(TCP校验和是一个端到端的校验和,由发送端计算,然后由接收端验证。其目的是为了发现TCP首部和数
据在发送端到接收端之间发生的任何改动。如果接收方检测到校验和有差错,则TCP段会被直接丢弃。)
(超时重传机制指在重发数据之前,等待确认应答到来的那个特定时间间隔。如果超过了这个时间仍未收到
确认应答,发送端将进行数据重发。)
③、tcp使用滑动窗口机制来实现流量控制,通过动态改变滑动窗口的大小实现拥塞控制。
流量控制:抑制发生端发送数据的速率,以便接收端来得及接收
拥塞控制:防止过多的数据一时间注入网络,避免网络负载过大;常见算法:慢启动、拥塞避免
17、死锁 如何避免?
死锁:当两个或多个线程在等待彼此释放所需的资源(锁定)并陷入无限等待的现象。
避免:1、改变加锁顺序:如果一个线程的进行需要一些锁,那么他必须按照确定好的顺 序获取锁,也就是只有获取从顺序上排在前面的锁后才能获取后面的锁;
例如:线程1已经获取了锁A,此时线程2的任务是获取锁A后再获取锁B,但是线程1已经获取了锁A了,所以线程2就要等线程1释放锁A才能获取锁B。
2、加锁时限:也就是设置线程获取锁的时候加一个超时时间,如果在获取锁的过程超过了超时时长就会放弃对该锁的请求。如果一个线程没有在超时时间内获取完所有他需要的锁,就会回滚释放之前已获取的锁。这样就可以避免多个线程间的无线等待。
3、死锁检测:把线程获取锁的信息记录到一个hashmap中,当一个线程请求锁失败的时候就会遍历这个map来判断是否会发生死锁,比如线程1请求锁A失败,他会遍历map看到线程2已经拥有锁A,然后判断线程2是否在请求自己已拥有的锁,如果线程2正在请求自己已拿到的锁,就可以知道此时发生了死锁。然后就可以通过释放所有锁,等待一段时间后再重试来避免发生死锁。
18、 进程和线程的关系?
①进程是程序的一次执行过程,是程序执行过程中分配和管理资源的基本单位,每个进程都有自己的地址空间,进程有五个基本状态,分别是:初始态、执行态、等待状态、就绪状态、终止状态
②线程是CPU调度和分派的基本单位,在同一进程下的所有线程都共享进程的所有资源
③关系:线程是进程的一部分,一个线程只有一个进程,而一个进程有多个线程。
④区别:进程是操作系统资源分配的基本单位,线程是任务调度和执行的基本单位。
线程是进程的一部分,线程也可以看做轻量级的进程
19、 Java线程池
①什么是线程池?
线程池是java中一种多线程的处理形式,处理过程会将任务交给线程池,任务的执行由线 程池来管理
②为什么要用线程池?
因为如果每个任务请求都创建一个线程去处理的话,服务器的资源会很快耗尽,且线程的创建和销毁都会花费更多时间和资源。使用线程池可以避免无限创建线程,当有额外的任务请求时,线程池会拿创建好的空闲线程去处理请求。
③常见的线程池:
Ⅰ、newSingleThreadExecutor:创建一个单线程化的线程池,只有一个单线程的线程
Ⅱ、newFixedThreadPoll:创建一个固定大小的线程池,每次有一个任务请求就会创建一个线程,直到线程达到线程池最大大小。
Ⅲ、newCachedThreadPool:创建一个可缓存的线程,如果线程池大小超过了处理任务所需的线程,那么就会回收部分空闲的线程。
Ⅳ、newScheduledThreadPool:创建一个无线大小的线程池,支持定时周期性执行任务。
④为什么线程池要用阻塞队列?
1、线程池创建线程需要获取mainlock这个全局锁,影响并发效率,阻塞队列可以很好的缓冲。
2、新任务的到达速率超过了线程池的处理速率,那么新到来的请求将累加起来,这样会耗尽资源
⑤ 四种拒绝策略:
1、AbortPolicy:直接抛出异常,阻止系统正常工作
2、CallerRunsPolicy:只有线程池未关闭,则由调用线程(主线程)执行任务
3、DiscardPolicy:丢弃新请求的任务,但不抛异常 (喜旧厌新)
4、DiscardOldestPolicy:丢弃当前队列最前面的任务,重新执行新请求的任务(喜新厌旧)
20、 JVM垃圾回收算法?
①复制清除法: 主要应用在新生区,但伊甸园区满了,还存活的对象会被复制到其中一个幸存区;垃圾回收时
会将在伊甸园区和幸存者from区还存活的对象复制到幸存者to区,然后将剩下未存活的对象进
行清理。如果幸存者to区没有内存存储复制过来的对象了,部分存活的对象就会进入老年区。
② 标记清除法: 主要应用在老年区,在垃圾回收时,第一次先会扫描并标记所有存活的对象,第二次则扫描并
清除未被标记的对象。
③标记整理清除法: 在扫描标记完所有存活的对象后,会把这些对象移动到一段,然后清除边界外的对象。
21、 垃圾回收器?
1、新生代:(新时代全是采用复制清除法)
①Serial:新生代串行收集器,是一个单线程的收集器,这种收集器在收集垃圾时,必须暂停其他的工作线程。
②ParNew:新生代并行收集器,是Serial的多线程版本。
③Parallel Scavenge:吞吐量优先收集器,与ParNew类似,该收集器有一个 GC自适应调节策略 ,
该策略会动态设置一些参数比如新生区大小,伊甸园区和幸存者区的大小比例等,以达到一个最高吞吐量。
[ 吞吐量是指运行代码时间/(运行代码时间+垃圾清除时间) ]
2、老年代:
①Serial Old: 老年代串行收集器,同样也是单线程的收集器,采用的是****标记整理法****。
②Parallel Old:Parallel Scavenge的老年代版本,采用****标记整理法****。
③CMS:以获取最短回收停顿时间为目标的收集器,适用于注重服务的响应速度,
希望系统停顿时间最短的场景。采用****标记清除法****
3、G1收集器:用于新生代和老年代,面向服务端应用的收集器,采用****标记整理法****
22、 JVM 新生代 vs 老年代
新生代主要存放新创建的对象,内存相比于老年代相对较小,垃圾回收也比较频繁。新生代分为一个伊甸园
区和两个幸存者区,新创建的对象会诞生于伊甸园区。当垃圾回收时,垃圾回收器会扫描伊甸园区和幸存者
from区,并将还存活的对象复制到幸存者to区,然后清除剩余的对象。当某些对象的存活的时间已满某个阀
值就会被转移到老年代。新生代主要采用的回收算法是复制清除法,以空间换时间的方式来回收垃圾。
老年代主要存放存活较久的对象,内存相比于新生代也相对较大,垃圾回收也没那么频繁。老年代主要采用
标记整理法来清除垃圾,这样可以避免产生内存碎片,当时间也花费更多。
23、为什么innodb不用哈希表、二叉树、红黑树
1、为什么不用b树:
b+树只在叶子节点存储数据,其余节点是只起索引的作用,且b+树的叶子节点又是一个双向链表的结构;
而b树在每个节点都存有数据的指针,因此在随机查询的时候(即随机一个where=),b树可能会带来大量的随机
磁盘I/O操作,而b+树可直接遍历叶子节点的链表顺序查询,因此b+树在随机查询和范围查询方面比b树效高,
2、为什么不用哈希表:
哈希表虽然有O(1)的时间复杂度的单行查询效率,但是哈希表它存储的数据本身就不连续,因此对于范围查
询、排序、模糊查询这些可能会导致全表扫描,从而降低了查询效率
3、二叉树包括AVL和红黑树这些树和B+树在相同的数据量下,二叉树的深度会比B+树深很多,而数据库大部分情
况下是在磁盘上查数据,深度越深代表磁盘的I/O次数越多,代表查询时间越长,且更耗费资源。
24、mysql和redis各自优势和缺点
1、mysql是关系型数据库,数据存放在磁盘上,但mysql的缓存机制也能将sql文本及缓存结果存放到内存中
mysql的优势是能存放大量的数据,功能强大,支持sql查询,可以实现一些关联查询及数据统计,一般用
于基本数据的持久化。
mysql的缺点是由于数据读写涉及到磁盘 I/O操作,数据读取相比于redis也相对较慢。
2、redis是非关系型数据库,数据一般存放在内存,但也有AOF和RDB两种方式来支持数据持久化。
redis的优势是读写速度快,所以一般用于存放一些频繁使用的数据,比如排行榜、粉丝这些。redis一般
也作为缓存工具来使用,它可以设置数据过期时间,这一功能更利于数据缓存。支持多种数
据类型key-value的value可以是string、list、hash、set、zset。支持主从复制,主机会自动
将数据同步到从机, 从而进行读写分离。
redis的缺点是由于数据存放在内存,因此数据量不能过大,且不适合一些有复杂逻辑关系的存储。
25、linux发送一条指令到回显经历了什么过程
26、什么是进程同步,进程为什么要同步,同步的方法?
当多个进程协同完成一些任务的时候,不同进程的执行进度是不一样的,比如A、B两个进程要协同完成一次算,A执行到一半要等待B的执行结果,于是会停下来让B执行;B执行完后将结果给A,A又继续执行。这种协作进程间相互等待对方消息或结果、互相合作的过程叫进程同步。
为什么?
①、为了解决资源共享问题 ,在操作系统中,多个进程的执行过程是异步的,如果多个进程要对同一共享资源进行操作时,如果随意进行操作,则会出现数据不准确,系统混乱的问题。因此必须要由操作系统为他们统一分配资源,也就是若干个进程要使用同一共享资源时,在任何时刻最多允许一个进程去使用,其他进去必须等待,直到占用资源的进程释放资源。也就是要实现进程同步。
②、为了相互合作完成某种任务,例如消费者生产者问题,一个进程负责生产,一个进程负责消费,当商品都消费完后,消费进程会进入睡眠状态并发送信号唤醒生产进程进行生产商品,商品内存已满,生产进程会进入睡眠状态并发送信号唤醒消费进程进行消费。并通过这种循环往复的同步方式以此完成生产消费任务。
方法:①加互斥锁:只允许一个进程在同一时刻占用同一资源
②信号量:允许一定数量的进程在同一时刻占用同一资源
27、进程与程序的区别?
进程是程序的一次执行,且可以并发执行,进程是系统进行资源分配和调度的基本单位。
程序是静态的指令集合,是永远存在的;而进程是程序动态的一次运行活动,有开始有结束。
1个程序可以对应多个进程,但1个进程只能对应1个程序。
程序相当于写好的剧本,而进程就相当于按照这个剧本的演出。
28、操作系统里的堆栈是什么?java里的堆栈是什么?
29、为什么要hashCode?
哈希值是hashCode方法根据一定的规则将对象的相关信息(地址,属性等)转换成一个数值,哈希值的存在主要是用于查找的便捷性,比如hashMap和Hashtable这些类在查找时,哈希值则用来
确定在哈希表中对象的存储位置。
30、讲讲equals,讲讲hashMap的equals?
equals是Object类的一个方法,其底层就是==比较两个类的地址是否相等。所以其他类为了实现具体功能,
往往要重写该方法,比如String类重写该方法对两个不同地址值的字符串只要其内容相等就判断相等;
再比如hashMap里的eqauls方法重写后,对两个不同地址的map会对其内容进行判断,如果其内容全都相同,则这两个map也相同。
31、from区满了怎么办,强引用、软引用、弱引用。
一个对象如果大于伊甸源区,它被创建的时候不会在伊甸园诞生,而是直接在老年区诞生,如果老年区也装不下,则直接报内存溢出错误。如果from区(或to区)满了,就会被放到老年区。
强引用就是指平时一般用的声明一个引用变量等于一个new对象。对于强引用的对象,即使是内存已满,也不会被垃圾回收器回收,而是报OOM。
对于软引用的对象,如果内存没有满,垃圾回收器扫描到他时,不会回收;当内存已满,就会回收软引用的对象。
对于弱引用的对象,只要垃圾回收器扫描到,就会回收。
32、垃圾回收机制为什么要分代?大对象和小对象的回收不同?
首先不同对象的生命周期是不一样的,比如Java程序里的session对象或一些经常使用的底层的对象的生命周期很长,一般伴随着整个程序的开启到结束,而有些对象只是临时创建来处理数据的比如一些String类或工具类,这些类的生命周期就很短,经常需要回收,如果不分代的话;生命周期长的对象和短的对象都在同一大块堆空间,每次扫描都会花大量时间,而且都会扫描到那些生命周期长的对象。所以引进分代后就可以将生命周期短的分一代,每次扫描都先轻GC,当内存不足时再重GC。
大对象一般会因为大小大于年轻代,或者设置的具体阈值大小,就好被放到老年区,通过标记清理法回收;
小对象一般会被创建在年轻代,通过复制清楚法回收;
33、redis的内存淘汰机制?
34、close_time和wait_time的区别
close_wait是被动方收到主动方关闭连接请求后发送确定报文后进入的状态,该状态是为了保证应用层的数据传输完,被动方才主动发送断开连接请求。
time_wait是主动方发送完ACK确认报文后,进入一个2MSL的等待时间,首先是为了保证最后发送的ACK报文能顺利到达,防止ACK报文丢失后,被动方不断发送FIN报文迟迟不能断开连接。其次是为了防止之前可能遗留在通信过程中的报文对下一次新连接进行干扰。