首页 / 面试 / java面经合集(面试遇到的)
java面经合集(面试遇到的)
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了java面经合集(面试遇到的),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含28288字,纯文字阅读大概需要41分钟。
内容图文
JDK
jdk8的新特性
- Lambda表达式
- 函数式接口
- *方法引用和构造器调用
- Stream API
- 接口中的默认方法和静态方法
- 新时间日期API
反射
动态的获取信息以及动态调用对象的方法: 3种方式
1 通过Object类的getClass方法来获取
2 使用类名加“.class”的方式即会返回与该类对应的Class对象。
3 使用Class.forName方法
数组和链表的区别
- 数组支持随机访问,而链表不支持。
- 数组使用的是连续内存空间对 CPU 的缓存机制友好,链表则相反。
- 数据的大小固定,而链表则天然支持动态扩容。
? 看面经的数据结构内容.
Redis的优缺点
redis数据存在内存中,所以读写非常快,redis还可以做缓存,分布式锁, 消息队列,还支持事务,持久化等/
缺点,
由于据存在内存中,,所以单台机器存储的数据量跟机器本身的内存大小有关。
修改配置文件,进行重启,将硬盘中的数据加载进内存,时间比较久。在这个过程中,redis不能提供服务。
redis 做分布式锁
(1)获取锁的时候,使用setnx加锁,并使用expire命令给锁加一个超时时间,超过该时间则自动释放锁,锁的value值为一个随机生成的UUID,通过此在释放锁的时候进行判断。
(2)获取锁的时候还设置一个获取的超时时间,若超过这个时间则放弃获取锁。
(3)释放锁的时候,通过UUID判断是不是该锁,若是该锁,则执行delete进行锁释放。
redis的同步数据
AOF 和 RDB 和事务
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OU6atEbc-1617329888291)(C:\Users\Zhang\Desktop\59AA723F9A55D38C06C4EE0006904F5A.png)]
缓存问题
雪崩: 缓存在同一时间大面积失效.请求都直接搭载了数据库上.
1 采用redis集群,防止单机出现问题整个服务器都没办法使用.
2限流避免同时处理大量的请求.
3 设置缓存永不失效(可能会造成内存满)
缓存击穿:在高并发下,多线程同时查询同一个资源,如果缓存中没有这个资源,那么这些线程都会去数据库查找,对数据库造成极大压力,
解决方案:后台定义一个job(定时任务)专门主动更新缓存数据. 或者,分级缓存
穿透:缓存中没有,直接在数据库中查找:
解决方案, 做好参数校验,不合法的参数请求直接抛出,异常, 信息返回给客户端,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a3ACDx1j-1617329888298)(C:\Users\Zhang\Desktop\0cecbf246bd2fef86a67b155feb8871.jpg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7Je3h2eK-1617329888303)(C:\Users\Zhang\Desktop\939b5ff2dd3ffc97726a5d995c3f91a.jpg)]
MYSQL
语句
SELECT * FROM student WHERE Python>=50 AND Python<=90; 查询python 成绩大于50 小于90 的
SELECT * FROM student ORDER BY Python DESC ; 按照成绩降序排列/降序
SELECT SUM(Java),SUM(Python),SUM(PHP)FROM student; //聚合函数的使用
SELECT Sno,avg( score ) FROM score GROUP BY Sno HAVING avg( score ) > 60 查询平均成绩大于60分的同学的学号和平均成绩
查询单科成绩前三 SELECT * FROM student ORDER BY Python DESC LIMIT 3;
SELECT (SELECT Java FROM student WHERE sName = '张三')
+ (SELECT Python FROM student WHERE sName = '张三')
+ (SELECT PHP FROM student WHERE sName = '张三') AS '总成绩'
SELECT (SELECT Java FROM student LIMIT 1 )/3 + (SELECT Python FROM student LIMIT 1)/3 +
(SELECT Php FROM student LIMIT 1)/3 AS '平均成绩' FROM student where sName = '勾八'
Group By 根据(by)一定的规则进行分组(Group)”。
作用:通过一定的规则将一个数据集划分成若干个小的区域,然后针对若干个小区域进行数据处理**。
WHERE 关键字在使用集合函数时不能使用,所以在集合函数中加上了HAVING来起到测试查询结果是否符合条件的作用。
having称为分组过滤条件,也就是分组需要的条件,所以必须与group by联用。
ORDER BY 语句用于对结果集进行排序。
limit 子句用于限制查询结果返回的数量。
## 索引
索引失效的情况: 1 范围条件查询导致索引失效 2 .like 以通配符开头(%abc)导致索引失效 (解决方法:使用覆盖索引)
3 or,用它来连接索引会失效
mysql的索引有哪两种,他们的特点分别是什么,Innodb的底层是怎么实现的 (B+树)B+树的特点,B树是什么?
索引的好处: 提高系统性能
优点. 1 可以保证数据库表中的每一行数据的唯一
? 2 可以加快索引的速度
? 3 可加快表与表之间的连接
? 4 可以减少查询和排序的时间
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zJUSP9pN-1617329888307)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20210321154511310.png)]
## 聚集索引非聚集索引
聚集索引:数据行的**物理顺序**与列值的**逻辑顺序**相同,
聚集索引一个表只能有一个,而非聚集索引一个表可以存在多个
聚集索引存储记录是物理上连续存在,而非聚集索引是逻辑上的连续,物理存储并不连续
聚集索引:物理存储按照索引排序;聚集索引是一种索引组织形式,索引的键值逻辑顺序决定了表数据行的物理存储顺序。
非聚集索引:物理存储不按照索引排序;非聚集索引则就是普通索引了,仅仅只是对数据列创建相应的索引,不影响整个表的物理存储顺序。
索引是通过二叉树的数据结构来描述的,我们可以这么理解聚簇索引:索引的叶节点就是数据节点。而非聚簇索引的叶节点仍然是索引节点,只不过有一个指针指向对应的数据块。
优势与缺点:
聚集索引插入数据时速度要慢(时间花费在“物理存储的排序”上,也就是首先要找到位置然后插入),查询数据比非聚集数据的速度快。
## 内连接
内连接(INNER JOIN):有两种,显式的和隐式的,返回连接表中符合连接条件和查询条件的数据行。隐式的内连接,没有INNER JOIN,
## 外连接
外连不但返回符合连接和查询条件的数据行,还返回不符合条件的一些行。外连接分三类:左外连接、右外连接和全外连接
三者的共同点是都返回符合连接条件和查询条件的数据行
左外连接还返回左表中不符合连接条件只符合查询条件的数据行。
右外连接还返回右表中不符合连接条件只符合查询条件的数据行。
全外连接还返回左表中不符合连接条件只符合查询条件的数据行,并且还返回右表中不符合连接条件只符合查询条件的数据行。
## B+树 和hash 索引.
区别
- hash索引更适合的是等值查询,B+树更适合范围查询检索,
- Hash索引没办法利用索引完成排序
- Hash索引不支持多列联合索引的最左匹配原则
- 在有大量重复键值情况下,哈希索引存在哈希碰撞所以效率也是极低的
B树就是二叉搜索树。具有的特点如下:
(1)所有非叶子结点最多拥有两个儿子;
(2)所有结点存储一个关键字;
(3)非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树。
B+树的特点:
(1) 关键字都出现在叶子结点的链表中,而且关键字恰好有序;
(3) 非叶子结点相当于索引,叶子结点相当于存储数据的数据层;
# JVM垃圾回收算法
## 标记清除
首先标记出所有需要回收的对象,,在标记完成后统一回收掉被标记的对象 (老年代)
缺点:第一个是执行效率不稳定,第二个是内存空间的碎片化问题
## 标记复制
将可用内存按容量划分为大小相等的两块,每次使用其中的一块,这一块用完了就将还存活者的对象复制到另一块上面(新生代)
缺点:内存缩小到原来的一般
不过新生代的98%的对象熬不过第一轮收集. 所以eden区和幸存区大小比例是8:1
## 标记整理
让所有存活的对象都移向内存空间的一端,,然后直接清理掉边界以外的内存 (老年代.)
# 多线程
线程过多会造成:线程的生命周期开销非常高,消耗过多的 CPU,降低稳定性JVM
线程是程序执行的基本单位,
进程是资源分配的基本单位
进程和线程的区别:1一个程序至少有一个进程,一个进程至少有一个线程
2 线程的划分尺度小于进程,使得多线程程序的并发性高。
3 进程在执行过程中拥有独立的内存单元,而多个线程共享内存
4 线程不能独立执行
多线程的同步和异步都可以达到避免线程阻塞的目的,从而提高软件的可响应性,
线程同步:多个线程同时访问同一资源
线程异步:访问资源在空闲等待时同时访问其他资源
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TGYEhkhR-1617329888311)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20210322123033837.png)]
## 并发编程的优缺点
:提高CPU的利用率,缺点是可能会出现内存泄漏,线程不安全.死锁等问题,
内存泄漏的原因: 长生命周期的对象持有短生命周期的引用,导致本应该被回收的对象没被回收.
? (内存泄漏是指不再被使用的对象或者变量一直被占据在内存中)
出现线程安全问题的原因:原子性问题 可见性问题 有序性问题,可用synchronized关键字解决
死锁产生的原因和解决办法:
破坏互斥条件:这个条件我们没有办法破坏,因为我们用锁本来就是想让他们互斥的
破坏请求与保持条件:一次性申请所有的资源。
破坏不剥夺条件:占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源。
破坏循环等待条件:靠按序申请资源来预防。
## CycliBarriar 和 CountdownLatch 有什么区别?
CountDownLatch与CyclicBarrier都是用于控制并发的工具类,都可以理解成维护的就是一个计数器,但是这两者还是各有不同侧重点
1 CountDownLatch强调一个线程等多个线程完成某件事情。CyclicBarrier是多个线程互等,等大家都完成,再携手共进。
2 调用CountDownLatch的countDown方法后,当前线程并不会阻塞,会继续往下执行;而调用CyclicBarrier的await方法,会阻塞当前线程,直到CyclicBarrier指定的线程全部都到达了指定点的时候,才能继续往下执行.
3 CountDownLatch是不能复用的,而CyclicLatch是可以复用的。
## 常用的并发工具类有哪些?
Semaphore(信号量)-允许多个线程同时访问:Semaphore 就是一个信号量,它的作用是限制某段代码块的并发数**Semaphore(信号量)可以指定多个线程同时访问某个资源。**
CountDownLatch(倒计时器): **CountDownLatch是一个同步工具类,用来协调多个线程之间的同步** 这个工具通常用来控制线程等待,它可以让某一个线程等待直到倒计时结束,再开始执行。
CyclicBarrier(循环栅栏): CyclicBarrier 和 CountDownLatch 非常类似,它也可以实现线程间的技术等待,但是它的功能比 CountDownLatch 更加复杂和强大。
## 多线程的实现方式
1.直接继承thread类;2.实现runnable接口 ; 3Callable 接口 4 Executors工具类创建线程池
1的 三个步骤:继承thread 重写RUN方法,2实例化子类,3 调用start
2 的三个步骤:myRunnable实现Runnable接口重写run;2以myRunnable作为target创建Thead对象 3 start;
1.Runnable和Thread相比优点有:
(1)由于Java不允许多继承,因此实现了Runnable接口可以再继承其他类,但是Thread明显不可以
(2)Runnable可以实现多个相同的程序代码的线程去共享同一个资源,而Thread并不是不可以,而是相比于Runnable来说,不太适合
#### Run和start的区别:
start() 方法用于启动线程,run() 方法用于执行线程的运行时代码。run() 可以重复调用,而 start() 只能调用一次。
#### 为什么我们不能直接调用 run() 方法?
调用 start 方法方可启动线程并使线程进入就绪状态,而 run 方法只是 thread 的一个普通方法调用,还是在主线程里执行。
## 线程的生命周期
由于cpu需要在多条线程中切换因此线程状态也会在多次运行和阻塞之间切换
新建:新创建了一个线程对象。
就绪:线程创建后,调用 start()方法,该线程处于就绪状态,等待被线程调度选中,获取cpu的使用权。
运行: 线程获得了cpu时间片进入可运行状态,执行程序代码; yield 使当前线程从执行状态(运行状态)变为可执行态(就绪状态)。
阻塞:处于运行状态中的线程由于某种原因,暂时放弃对 CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被 CPU 调用以进入到运行状态。 wait sleep join sleep()方法声明抛出 InterruptedException
死亡:线程run()、main()方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。
stop(); interrupt();
## 线程间通信的几种实现方式
线程间通信的模型有两种:共享内存和消息传递,
*1 volatile* 关键字:使用共享内存的思想,大致就是多个线程同时监听一个变量,当这个变量发生变化的时候 ,线程能够感知并执行相应的业务。这也是最简单的一种实现方式
2 *Object*类提供了线程间通信的方法:*wait()*、*notify()*、*notifyaAl()*,它们是多线程通信的基础
3 使用JUC工具类 CountDownLatch
4 使用 ReentrantLock 结合Condition类的await()/signal()/signalAll()
5 基本LockSupport实现线程间的阻塞和唤醒
锁自旋 :因为线程阻塞涉及到用户态和内核态切换的问题,不妨让等待锁的线程不被阻塞,而是在边界做忙循环,
锁的升级的目的:锁升级是为了减低了锁带来的性能消耗。
## Volatile
Java 提供了 volatile 关键字来保证可见性和禁止指令重排。 volatile 确保一个线程的修改能对其他线程是可见的。当一个共享变量被 volatile 修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。
## synchronized的底层原理
Java的JVM内存区域中一个对象在堆区创建,创建后的对象由三部分组成:
实例对象 :存放类的属性数据信息,包括父类的属性信息,这部分内存按4字节对齐。
填充字节:必须是八的倍数
对象头:klasspoint 和 markword
1. `Klass Point`(类型指针):是对象指向它的类元数据的指针,**虚拟机通过这个指针来确定这个对象是哪个类的实例**。
2. `Mark Word`(标记字段):**这一部分用于储存对象自身的运行时数据**,如哈希码,`GC`分代年龄,锁状态标志 锁指等,这部分数据在32bit和64bit的虚拟机中大小分别为32bit和64bit,考虑到虚拟机的空间效率,Mark Word被设计成一个非固定的数据结构以便在极小的空间中存储尽量多的信息,它会根据对象的状态复用自己的存储空间(跟[ConcurrentHashMap](https://mp.weixin.qq.com/s?__biz=MzI4NjI1OTI4Nw==&mid=2247487563&idx=1&sn=0a223ae2bba963e3ac40b7ce6d9ecd56&scene=21#wechat_redirect)里的标志位类似),详细情况如下图:
synchronized不论是修饰方法还是代码块,都是通过持有修饰对象的来实现同步,`synchronized`锁对象是存在对象头`Mark Word`。synchronized的对象锁,锁标识位为10,其中指针指向的是monitor对象(也称为管程或监视器锁)的起始地址。每个对象都存在着一个 monitor[4] 与之关联。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wx5YLiJl-1617329888317)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20210331095350655.png)]
对于同步方法,JVM采用ACC_SYNCHRONIZED标记符来实现同步。对于同步代码块。JVM采用monitorenter monitorexit两个指令来实现同步。
**可以把执行monitorenter指令理解为加锁,执行monitorexit理解为释放锁。每个对象维护着一个记录着被锁次数的计数器。未被锁定的对象的该计数器为0,当一个线程获得锁后,该计数器自增变为 1 **,当同一个线程再次获得该对象的锁的时候,计数器再次自增。**当同一个线程释放锁的时候,计数器再自减。当计数器为0的时候。锁将被释放,其他线程便可以获得锁。**
## volatile与synchronized区别
volatile 1保证可见性 即一个线程修改某个变量的值,这个新值对其他线程来说是可见的.
2 有序性 禁止指令重排
3 能保证单词读写的原子性, 但不能保证I++这种的原子性;
仅靠volatile不能保证线程的安全性。(原子性)
①volatile轻量级,只能修饰变量。synchronized重量级,还可修饰方法
②volatile只能保证数据的可见性,不能用来同步,因为多个线程并发访问volatile修饰的变量不会阻塞。
synchronized不仅保证可见性,而且还保证原子性,
## lock
lock的存储结构:一个int类型状态值(用于锁的状态变更),一个双向链表(用于存储等待中的线程)
lock获取锁的过程:本质上是通过CAS来获取状态值修改,如果当场没获取到,会将该线程放在线程等待链表中。
lock释放锁的过程:修改状态值,调整等待链表。
在整个实现过程中,lock大量使用CAS+自旋。因此根据CAS特性,lock建议使用在低锁冲突的情况下。官方对synchronized做了大量的锁优化(偏向锁、自旋、轻量级锁)。因此在非必要的情况下,建议使用synchronized做同步操作。
## synchronized与lock 的区别
实现层面:synchronized(JVM层面)、Lock(JDK层面)
响应中断:Lock 可以让等待锁的线程响应中断,而使用synchronized时,等待的线程会一直等待下去,不能够响应中断;
读写锁:Lock可以提高多个线程进行读操作的效率
可实现公平锁:Lock可以实现公平锁,而sychronized天生就是非公平锁
## synchronized与Reentrantlock 的区别
synchronized 加锁和解锁都是自动进行,易于操作,但不灵活.
Reentrantlock 手动进行,不宜与操作但是非常灵活
synchronized 不可以响应中断,线程获取不到所就一直等待.
Reentrantlock 可以响应中断
## **集合框架怎么解决线程不安全**
list:有序可重复 vector
set:无序不可重复 collections工具类中的synchronizedSet();
map:key无序不可重复, value 无序不可重复 hashtable;
## 线程池
优点: 1减少对象创建销毁的开销,降低资源消耗
2 提高响应速度。提高系统资源的使用率,避免过多资源竞争,避免堵塞。
3 提高线程的可管理性。
线程池有哪些 :
(1)newSingleThreadExecutor:创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务
(2)newFixedThreadPool:创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。
(3) newCachedThreadPool:创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务
(4)newScheduledThreadPool:创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。
?
7大参数: 1 核心线程数 (最小线程数) 2 最大线程数,3存活时间,4 超时时间, 5 阻塞队列,6线程工厂,7拒绝策略
线程池中如果循环队列满了以后会怎么样? 触发拒绝策略机制
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vHPHEdQg-1617329888320)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20210321122524816.png)]
丢弃最老的策略
线程池都有哪些状态?
running:这是最正常的状态,接受新的任务,处理等待队列中的任务。
shutdown:不接受新的任务提交,但是会继续处理等待队列中的任务。
stop:不接受新的任务提交,不再处理等待队列中的任务,中断正在执行任务的线程。
tidying:所有的任务都销毁了,workCount 为 0,线程池的状态在转换为 TIDYING 状态时,会执行钩子方法 terminated()。
TERMINATED:terminated()方法结束后,线程池的状态就会变成这个。
# SpringMVC优点:
1 通过把模型-试图-控制器分离将WEB层进行解耦,把复杂的web应用分为逻辑清晰的几部分,简化开发.
2 与Spring框架集成(如IoC容器、AOP等)
3 支持各种请求资源的映射策略。
## 5大组件
1.DispatcherServlet:前端控制器,接收请求,调用其他组件处理请求响应请求,相当于转发器,中央控制器,是整个控制流程的中心。
2.HandlerMapping: 处理器映射,主要功能是实现请求派发,找到请求和控制器之间的对应关系。
3.Controller:控制器,接收处理前端控制器分发的请求,将执行的结果(ModelAndView)返回给前端控制器。
4.ModelAndView:封装数据模型和视图信息。
5.ViewResolver:视图解析器,根据视图名称解析后返回一个真正的页面。
流程图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y67nAZhT-1617329888322)(C:\Users\Zhang\Desktop\f98f195a043efec539c463d2d2523c8(1)].jpg)
# Spring
优点:1方便解隅,简化开发
2AOP编程的支持。通过Spring提供的Aop功能,方便进行对面向切向的编程
3声明事务的支持
4方便集成各种优秀的框架
spring声明式事务实现的2种方式:1 基于注解的方式 transactional 2 基于XML文件的配置方式transaction manage
Spring是一个**轻量**级的**控制反转**(IoC)和**面向切面**(AOP)的**容器**框架
IOC : 将原本在程序中手动创建的控制权交给Spring
AOP : 与业务无关, 把业务模块调用的逻辑封装起来.减少系统的重复代码,降低模块间的耦合度.
SpringAOP与aspectAOP的区别:
SpringAOP是运行时增强,属于动态代理.功能简单,好操作
aspectAOP 是编译时增强,属于静态代理,功能强大. 功能简单
Spring中bean 的作用域:request session global-session prototype ;
IOC的设计模式 工厂模式: 单例模式,代理模式
## ${}和#{}的区别:
1.#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by "111", 如果传入的值是id,则解析成的sql为order by "id".
2.$将传入的数据直接显示生成在sql语句中。如:orderby将传入的数据直接显示生成在sql中。如:orderbyuser_id$,如果传入的值是111,那么解析成sql时的值为order by user_id, 如果传入的值是id,则解析成的sql为order by id.
3.#方式能够很大程度防止sql注入。
4.$方式无法防止Sql注入。
5.$方式一般用于传入数据库对象,例如传入表名.
6.一般能用#的就别用$.
## springAOP的几个注解
: Before ,around AfterReturn ,AfterThrowing After PointCut
bean的生命周期
1. 实例化 Instantiation
2. 属性赋值 Populate
3. 初始化 Initialization
4. 销毁 Destruction
Spring是核心,提供了基础功能;
Spring MVC 是基于Spring的一个 MVC 框架 ;通过把模型-试图-控制器分离将WEB层进行解耦,把复杂的web应用分为逻辑清晰的几部分,简化开发.
Spring Boot 是为简化Spring配置的快速开发整合包;
# Http//https
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hz10nqBB-1617329888324)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20210321151502746.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-40CznB3M-1617329888327)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20210321151530406.png)]
5 层体系结构 1 物理层 2 数据连路层 3 网络层 4 运输层 5 应用层
7层体系结构 1 物理层 2 数据连路层 3 网络层 4 运输层 5 会话层,6 表示层,7 应用层;
# Linux
```linux
ps -l 列出与本次登录有关的进程信息;
ps -aux 查询内存中进程信息;
ps -aux | grep *** 查询***进程的详细信息;
top 查看内存中进程的动态信息;
kill -9 pid 杀死进程。
ThreadLocal
我们可以得知 ThreadLocal 的作用是:提供线程内的局部变量,不同的线程之间不会相互干扰,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或组件之间一些公共变量传递的复杂度。
- 线程并发: 在多线程并发的场景下
- 传递数据: 我们可以通过ThreadLocal在同一线程,不同组件中传递公共变量
- 线程隔离: 每个线程的变量都是独立的,不会互相影响
syn和threadlocal 的区别
同步机制采用’以时间换空间’的方式, 只提供了一份变量,让不同的线程排队访问 | ThreadLocal采用’以空间换时间’的方式, 为每一个线程都提供了一份变量的副本,从而实现同时访问而相不干扰 |
---|---|
多个线程之间访问资源的同步 | 多线程中让每个线程之间的数据相互隔离 |
在JDK8中 ThreadLocal
的设计是:每个Thread
维护一个ThreadLocalMap
,这个Map的key
是ThreadLocal
实例本身,value
才是真正要存储的值`Object.
这样设计之后每个Map存储的Entry数量就会变少。因为之前的存储数量由Thread的数量决定,现在是由ThreadLocal的数量决定。在实际运用当中,往往ThreadLocal的数量要少于Thread的数量。()
当Thread销毁之后,对应的ThreadLocalMap也会随之销毁,能减少内存的使用。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6lDMtmR2-1617329888329)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20210311094132132.png)]
弱引用的内存泄漏
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3xcSZNuC-1617329888331)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20210311094357358.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OiEvdO2F-1617329888333)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20210311094514915.png)]
- 使用完ThreadLocal,调用其remove方法删除对应的Entry
- 使用完ThreadLocal,当前Thread也随之运行结束
这就意味着使用完ThreadLocal,CurrentThread依然运行的前提下,就算忘记调用remove方法,弱引用比强引用可以多一层保障:弱引用的ThreadLocal会被回收,对应的value在下一次ThreadLocalMap调用set,get,remove中的任一方法的时候会被清除,从而避免内存泄漏。
令牌桶和漏桶
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5vA4rbaa-1617329888334)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20210321115832631.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i7vfMTnA-1617329888336)(C:\Users\Zhang\AppData\Roaming\Typora\typora-user-images\image-20210321115905994.png)]
RabbitMQ
:RabbitMQ是一款开源的,Erlang编写的,基于AMQP协议的消息中间件
rabbitMQ的优点:
异步处理 - 相比于传统的串行、并行方式,提高了系统吞吐量。
应用解耦 - 系统间通过消息通信,不用关心其他系统的处理。
流量削锋 - 可以通过消息队列长度控制请求量;可以缓解短时间内的高并发请求。
日志处理 - 解决大量日志传输。
消息通讯 - 消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯。比如实现点对点消息队列,或者聊天室等。
缺点:系统可用性降低,系统复杂度提高 一致性问题
rabbitmq 的使用场景
(1)服务间异步通信
(2)顺序消费
(3)定时任务
(4)请求削峰
MQ 的常见问题有:
-
如何保证RabbitMQ消息的顺序性?
拆分多个 queue,每个 queue对应 一个 consumer; -
如何保证消息不被重复消费?或者说,如何保证消息消费时的幂等性?
保证消息的唯一性,就算是多次传输,不要让消息的多次消费带来影响;保证消息等幂性;
RabbitMQ基本概念
**1.1 消息代理(message brokers):**大家可以理解为RabbitMQ 服务器,起到了消息接收,持久化和转发等作用。
**1.2 发布者(publishers)或生产者(producers):**消息的产生来源,具有生产消息的角色。
**1.3 消费者(consumers):**消息的接收者,消费消息的角色。
**1.4 交换机(exchange):**用于接收生产者生产的消息,并按照一定的路由规则将消息转发到匹配的队列。
**1.5 消息队列(queue):**根据指定的绑定规则来接受交换机内自身感兴趣的的消息。
**1.6 绑定(binding):**将消息队列和交换机绑定在一起,绑定时指明队列匹配消息的匹配规则(可以理解为队列的兴趣爱好)。
**1.7 路由键(routingKey):**生产者发送到交换机内的消息需要带上自己的路由键,交换机根据消息的路由键去和队列绑定时声明的binding匹配。
RabbitMQ的工作模式
1 简单模式
1.生产者产生消息,将消息放入队列
2.消费者监听消息队列,如果队列中有消息,就消费掉,消息被拿走后,自动从队列中删除
隐患 消息可能没有被消费者正确处理,已经从队列中消失了,造成消息的丢失
这里可以设置成手动的ack,但如果设置成手动ack,处理完后要及时发送ack消息给队列,否则会造成内存溢出
ack:消息确认机制
2 work工作模式
1.产生者将消息放入队列消费者可以有多个,消费者1,消费者2同时监听同一个队列,消息被消费。
2 C1 C2共同争抢当前的消息队列内容,谁先拿到谁负责消费消息
隐患:高并发情况下,默认会产生某一个消息被多个消费者共同使用
可以设置一个开关(syncronize) 保证一条消息只能被一个消费者使用)。
三.publish/subscribe发布订阅(共享资源)
1、每个消费者监听自己的队列;
2、生产者将消息发给broker,由交换机将消息转发到绑定此交换机的每个队列,每个绑定交换机的队列都将接收到消息。
X 为消息交换机,它指定消息按什么规则,路由到哪个队列
四.routing路由模式
1.消息生产者将消息发送给交换机按照路由判断
(P到X中间是路由关键字 :路由关键字,exchange根据这个关键字进行消息投递)
(X到Q是 绑定,它的作用就是把exchange和queue按照路由规则绑定起来)
2.根据业务功能定义路由字符串
3.从系统的代码逻辑中获取对应的功能字符串,将消息任务扔到对应的队列中。
4.业务场景:error 通知;EXCEPTION;错误通知的功能;传统意义的错误通知;客户通知;利用key路由,可以将程序中的错误封装成消息传入到消息队列中,开发者可以自定义消费者,实时接收错误;
五.topic 主题模式(路由模式的一种)
多了通配符
3.路由功能添加模糊匹配
消息如何分发?
若该队列至少有一个消费者订阅,消息将以循环(round-robin)的方式发送给消费者。每条消息只会分发给一个订阅的消费者。通过路由可实现多消费的功能
消息怎么路由?
生产者->路由->一至多个队列消息发布到交换器时,消息将拥有一个路由键(routing key),在消息创建时设定。通过队列路由键,可以把队列绑定到交换器上。消息到达交换器后,RabbitMQ 会将消息的路由键与队列的路由键进行匹配
消息基于什么传输?
由于 TCP 连接的创建和销毁开销较大,且并发数受系统资源限制,会造成性能瓶颈。
RabbitMQ 使用信道的方式来传输数据。信道是建立在真实的 TCP 连接内的虚拟连接,且每条 TCP 连接上的信道数量没有限制。
如何确保消息正确地发送至 RabbitMQ?
发送方确认模式
将信道设置成 confirm 模式(发送方确认模式),则所有在信道上发布的消息都会被指派一个唯一的 ID。
如何确保消息接收方消费了消息?
接收方确认机制
消费者接收每一条消息后都必须进行确认。只有消费者确认了消息,RabbitMQ 才能安全地把消息从队列中删除。
如何保证RabbitMQ消息的可靠传输?
消息不可靠的情况可能是消息丢失,劫持等原因;
丢失又分为:
生产者丢失消息、从生产者弄丢数据这个角度来看,RabbitMQ提供事务和发送方确认机制来确保生产者不丢消息;
消息列表丢失消息:处理消息队列丢数据的情况,一般是开启持久化磁盘的配置。
消费者丢失消息;自动确认消息模式改为手动确认消息即可!
计算机网络
1 TCP为什么需要3次握手,4次断开?
三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”。
因为TCP有个半关闭状态,假设A.B要释放连接,那么A发送一个释放连接报文给B,B收到后发送确认,这个时候A不发数据,但是B如果发数据A还是要接受,这叫半关闭。然后B还要发给A连接释放报文,然后A发确认,所以是4次。
2、TCP和UDP有什么区别?
TCP是传输控制协议,提供的是面向连接、可靠的字节流服务。通信双方彼此交换数据前,必须先通过三次握手协议建立连接,之后才能传输数据。
UDP是用户数据报协议,是一个简单的面向无连接的协议。UDP不提供可靠的服务。在数据数据前不用建立连接故而传输速度很快
3、交换机与路由器有什么区别?
①工作所处的OSI层次不一样,交换机工作在OSI第二层数据链路层,路由器工作在OSI第三层网络层
②寻址方式不同:交换机根据MAC地址寻址,路由器根据IP地址寻址
③转发速不同:交换机的转发速度快,路由器转发速度相对较慢。
TCP/IP的流量控制?
利用滑动窗口实现流量控制,
4 IO中同步与异步,阻塞与非阻塞区别**
同步和异步关注的是消息通信机制
同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了。
换句话说,就是由调用者主动等待这个调用的结果。
异步则是相反,调用*在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在调用*发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。
阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态****.
阻塞调用 :是指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。
**非阻塞:**结果返回之前,该函数不会阻塞当前线程,而会立刻返回。
ip地址分段
A类网络的IP地址范围为1.0.0.1-127.255.255.254;
B类网络的IP地址范围为:128.1.0.1-191.255.255.254;
C类网络的IP地址范围为:192.0.1.1-223.255.255.254、
5 TCP拥塞控制
防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。拥塞控制所要做的都有一个前提:网络能够承受现有的网络负荷。拥塞控制是一个全局性的过程,涉及到所有的主机、路由器,以及与降低网络传输性能有关的所有因素。
拥塞控制代价:需要获得网络内部流量分布的信息。在实施拥塞控制之前,还需要在结点之间交换信息和各种命令,以便选择控制的策略和实施控制。这样就产生了额外的开销。拥塞控制还需要将一些资源分配给各个用户单独使用,使得网络资源不能更好地实现共享。
几种拥塞控制方法:
慢开始(slow-start )、拥塞避免(congestion avoidance )、快重传( fastretransmit )和快恢复( fastrecovery )。
为什么TIME_WAIT状态还需要等2*MSL(Max SegmentLifetime,最大分段生存期)秒之后才能返回到****CLOSED状态呢?
数据链路层协议可能提供的服务?
链路访问、透明传输、可靠交付、流量控制、差错检测、差错纠正、半双工和全双工。
网桥的作用?
网桥是一个局域网与另一个局域网之间建立连接的桥梁
ARP是地址解析协议
DHCP协议
动态主机配置协议,是一种让系统得以连接到网络上,并获取所需要的配置参数手段。
ICMP
是InternetControl Message Protocol,因特网控制报文协议。它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。
网络接口卡(网卡)的功能?
(1)进行串行/并行转换。
(2)对数据进行缓存。
(3)在计算机的操作系统安装设备驱动程序。
(4)实现以太网协议。
7层协议
应用层
网络服务与最终用户的一个接口。
协议有:HTTP FTP TFTP SMTP SNMP DNS TELNET HTTPS POP3 DHCP
表示层
数据的表示、安全、压缩。(在五层模型里面已经合并到了应用层)
格式有,JPEG、ASCll、EBCDIC、加密格式等 [2]
会话层
建立、管理、终止会话。(在五层模型里面已经合并到了应用层)
对应主机进程,指本地主机与远程主机正在进行的会话
传输层
定义传输数据的协议端口号,以及流控和差错校验。
协议有:TCP UDP,数据包一旦离开网卡即进入网络传输层
网络层
进行逻辑地址寻址,实现不同网络之间的路径选择。
协议有:ICMP IGMP IP(IPV4 IPV6)
数据链路层
建立逻辑连接、进行硬件地址寻址、差错校验 [3] 等功能。(由底层网络定义协议)
将比特组合成字节进而组合成帧,用MAC地址访问介质,错误发现但不能纠正。
物理层
建立、维护、断开物理连接。(由底层网络定义协议)
内容总结
以上是互联网集市为您收集整理的java面经合集(面试遇到的)全部内容,希望文章能够帮你解决java面经合集(面试遇到的)所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。