java细节知识点学习2

谈谈ConcurrentHashMap

ConcurrentHashMap 同样也分为 1.7 、1.8 版,两者在实现上略有不同。
先来看看 1.7 的实现,下面是他的结构图:
在这里插入图片描述
是由 Segment 数组、HashEntry 组成,和 HashMap 一样,仍然是数组加链表。
Segment 是 ConcurrentHashMap 的一个内部类,主要的组成如下:

 1    static final class Segment<K,V> extends ReentrantLock implements Serializable {
 2
 3        private static final long serialVersionUID = 2249069246763182397L;
 4
 5        // 和 HashMap 中的 HashEntry 作用一样,真正存放数据的桶
 6        transient volatile HashEntry<K,V>[] table;
 7
 8        transient int count;
 9
10        transient int modCount;
11
12        transient int threshold;
13
14        final float loadFactor;
15
16    }

HashEntry 的组成:

在这里插入图片描述
和 HashMap 非常类似,唯一的区别就是其中的核心数据如 value ,以及链表都是 volatile 修饰的,保证了获取时的可见性。

原理上来说:ConcurrentHashMap 采用了分段锁技术,其中 Segment 继承于 ReentrantLock。不会像 HashTable 那样不管是 put 还是 get 操作都需要做同步处理,理论上 ConcurrentHashMap 支持 CurrencyLevel (Segment 数组数量)的线程并发。每当一个线程占用锁访问一个 Segment 时,不会影响到其他的 Segment。

下面是1.8:
1.7 已经解决了并发问题,并且能支持 N 个 Segment 这么多次数的并发,但依然存在 HashMap 在 1.7 版本中的问题。
1.7存在的问题需要解决那就是查询遍历链表效率太低。

因此,1.8做了数据结构的调整:
在这里插入图片描述
看起来是不是和 1.8 HashMap 结构类似?

其中抛弃了原有的 Segment 分段锁,而采用了 CAS (乐观锁)+ synchronized 来保证并发安全性。
在这里插入图片描述
也将 1.7 中存放数据的 HashEntry 改为 Node,但作用都是相同的。

其中的== val next 都用了 volatile 修饰==,保证了可见性。

1.8 在 1.7 的数据结构上做了大的改动,采用红黑树之后可以保证查询效率(O(logn)),甚至取消了 ReentrantLock 改为了 synchronized,这样可以看出在新版的 JDK 中对 synchronized 优化是很到位的。

这位博主的笔记很全,对里面源码的get put方法分析
https://blog.csdn.net/weixin_44460333/article/details/86770169

它的扩容机制(还需要再分析下源码!!!)

1.7版本

  1. 1.7版本的ConcurrentHashMap是基于Segment分段实现的
  2. 每个Segment相对于⼀个⼩型的HashMap
  3. 每个Segment内部会进⾏扩容,和HashMap的扩容逻辑类似
  4. 先⽣成新的数组,然后转移元素到新数组中
  5. 扩容的判断也是每个Segment内部单独判断的,判断是否超过阈值

1.8版本

  1. 1.8版本的ConcurrentHashMap不再基于Segment实现
  2. 当某个线程进⾏put时,如果发现ConcurrentHashMap正在进⾏扩容那么该线程⼀起进⾏扩容
  3. 如果某个线程put时,发现没有正在进⾏扩容,则将key-value添加到ConcurrentHashMap中,然后 判断是否超过阈值,超过了则进⾏扩容
  4. ConcurrentHashMap是⽀持多个线程同时扩容的
  5. 扩容之前也先⽣成⼀个新的数组
  6. 在转移元素时,先将原数组分组,将每组分给不同的线程来进⾏元素的转移,每个线程负责⼀组或多组的元素转移⼯作

Spring中Bean是线程安全的吗?(对于bean spring是如何创建的,需要看源码!!!)

spring只是根据你写的bean对对象进行创建,我们再去使用这个bean实际上spring是管不到的。因此
==Spring本身并没有针对Bean做线程安全的处理,==所以:

  1. 如果Bean是⽆状态的,那么Bean则是线程安全的
  2. 如果Bean是有状态的,那么Bean则不是线程安全的 另外,Bean是不是线程安全,跟Bean的作⽤域没有关系,Bean的作⽤域只是表示Bean的⽣命周期范围, 对于任何⽣命周期的Bean都是⼀个对象,这个对象是不是线程安全的,还是得看这个Bean对象本身。
bean的作用域

@scope
singleton: 默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。
prototype: 原型模式,理解为多例模式。每一次get这个bean都会产生过新的对象。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收。。
还有session,request,application是在web开发的情形下使用的。

linux基本的操作命令(*)

这位博主写的很好
https://blog.csdn.net/qq_23329167/article/details/83856430/

Maven中Package和Install的区别,还有deploy的作用

  1. Package是打包,把项目打成Jar或War包
  2. Install表示将Jar或War安装到Maven的本地仓库中
  3. deploy将项目部署在远程仓库

springcloud中的各个组件与dubbo的区别(*)

  1. Eureka:注册中⼼,⽤来进⾏服务的⾃动注册和发现
  2. Ribbon:负载均衡组件,⽤来在消费者调⽤服务时进⾏负载均衡
  3. Feign:基于接⼝的申明式的服务调⽤客户端,让调⽤变得更简单
  4. Hystrix:断路器,负责服务容错
  5. Zuul:服务⽹关,可以进⾏服务路由、服务降级、负载均衡等
  6. Nacos:分布式配置中⼼以及注册中⼼
  7. Sentinel:服务的熔断降级,包括限流
  8. Seata:分布式事务
  9. Spring Cloud Config:分布式配置中⼼
  10. Spring Cloud Bus:消息总线

    讲解看狂神的视频

Spring Cloud是⼀个微服务框架,提供了微服务领域中的很多功能组件,Dubbo⼀开始是⼀个RPC调⽤框 架,核⼼是解决服务调⽤间的问题,Spring Cloud是⼀个⼤⽽全的框架,Dubbo则更侧重于服务调⽤,所 以Dubbo所提供的功能没有Spring Cloud全⾯,但是Dubbo的服务调⽤性能⽐Spring Cloud⾼,不过 Spring Cloud和Dubbo并不是对⽴的,是可以结合起来⼀起使⽤的。

类加载器的双亲委派机制

JVM中存在三个默认的类加载器:

  1. BootstrapClassLoader
  2. ExtClassLoader
  3. AppClassLoader

AppClassLoader的⽗加载器是ExtClassLoader,ExtClassLoader的⽗加载器是 BootstrapClassLoader。 JVM在加载⼀个类时,会调⽤AppClassLoader的loadClass⽅法来加载这个类,不过在这个⽅法中,会先使用ExtClassLoader的loadClass⽅法来加载类,同样ExtClassLoader的loadClass⽅法中会先使⽤ BootstrapClassLoader来加载类,如果BootstrapClassLoader加载到了就直接成功,如果 BootstrapClassLoader没有加载到,那么ExtClassLoader就会⾃⼰尝试加载该类,如果没有加载到,那 么则会由AppClassLoader来加载这个类。

所以,双亲委派指得是,JVM在加载类时,会委派给Ext和Bootstrap进⾏加载,如果没加载到才由⾃⼰进 ⾏加载。

tomcat为什么要自定义加载器(还不够理解!!)

因为如果在一个tomcat里面加上好几个项目,然后这几个项目如果公用统一个类加载器的话,可能会造成冲突,比如我们同时写了几个相同的类名,但是里面类方法等等不一样,放在不同的项目中。这时候只用一个类加载器的话,就可能只加载一个类。

https://blog.csdn.net/varyall/article/details/81610620

泛型中extends和super的区别

  1. <? extends T>表示包括T在内的任何T的⼦类
  2. <? super T>表示包括T在内的任何T的⽗类

并发编程三要素?(*)

  1. 原⼦性:不可分割的操作,多个步骤要保证同时成功或同时失败
  2. 有序性:程序执⾏的顺序和代码的顺序保持⼀致
  3. 可见性:⼀个线程对共享变量的修改,另⼀个线程能⽴⻢看到

volatile关键字解析(*)

这个博主写的很好(简单易懂)

https://www.cnblogs.com/dolphin0520/p/3920373.html

Spring用到了哪些设计模式(设计模式仅懂几个,特别注意!!!!!)

在这里插入图片描述

这位博主写的详解:
https://zhuanlan.zhihu.com/p/66790602

简述CAP理论

CAP理论是分布式领域⾮常重要的⼀个理论,很多分布式中间件在实现时都需要遵守这个理论,其中:

  1. C表示⼀致性:指的的是分布式系统中的数据的⼀致性
  2. A表示可⽤性:表示分布式系统是否正常可⽤
  3. P表示分区容器性:表示分布式系统出现⽹络问题时的容错性

CAP理论是指,在分布式系统中不能同时保证C和A,也就是说在分布式系统中要么保证CP,要么保证 AP,也就是⼀致性和可⽤性只能取其⼀,如果想要数据的⼀致性,那么就需要损失系统的可⽤性,如果需 要系统⾼可⽤,那么就要损失系统的数据⼀致性,特指强⼀致性。 CAP理论太过严格,在实际⽣产环境中更多的是使⽤BASE理论,BASE理论是指分布式系统不需要保证数 据的强⼀致,只要做到最终⼀致,也不需要保证⼀直可⽤,保证基本可⽤即可。

图的深度遍历和广度遍历

深度优先遍历简称DFS(Depth First Search),广度优先遍历简称BFS(Breadth First Search),它们是遍历图当中所有顶点的两种方式。

  1. 图的深度优先遍历是指,从⼀个节点出发,⼀直沿着边向下深⼊去找节点,如果找不到了则返回上⼀层 找其他节点

在这里插入图片描述
我们假设从顶点A出发开始访问,那么可能的访问序列有:

  • A,D,C,E,B
  • A,D,E,C,V
  • A,C,D,B,E
  1. 图的⼴度优先遍历只是,从⼀个节点出发,向下先把第⼀层的节点遍历完,再去遍历第⼆层的节点,直 到遍历到最后⼀层

上述图从A出发,我们假设D,C,B分别是A指向的第一个、第二个和第三个节点,那么广度遍历的序列为:

  • A,D,C,B,E

二叉树的三种遍历

1. 前序遍历:根节点+左子树+右子树。
在遍历左子树和右子树时,仍然先访问根节点,然后遍历左子树,最后遍历右子树。

2.中序遍历:左子树+根节点+右子树。

在遍历左右子树时,仍然先遍历左子树,再遍历根节点,后遍历右子树。

3.后序遍历:左子树+右子树+根节点。
在遍历左右子树时,仍然先遍历左子树,在遍历右子树,后访问根节点。
在这里插入图片描述
先序遍历:ABCDEFGHK

中序遍历:BDCAEHGKF

后序遍历:DCBHKGFEA

排序算法(各大排序算法 *)

自己找到的排序算法图解,及代码分析
https://note.youdao.com/web/#/file/SVR0AF4BAD02B8F4532B2DDBCD9F40483D3/note/7B6A509D920E4799AB9F14EF804A3E9B/

TCP与UDP

== TCP 和 UDP是网络协议的传输层上的两种不同的协议==。
TCP的特点是面向连接的、可靠的字节流服务。客户端需要和服务器之间建立一个TCP连接,之后才能传输数据。数据到达之前对方就一直在等待,除非对方直接关闭连接,数据有序,先发先到。
**UDP是一种无连接、不可靠的数据发送协议。**发送方根据对方的ip地址发送数据包,但是不保证接收发接包的质量,数据无序还容易丢包。虽然UDP协议不稳定但是在即时通讯(QQ聊天、在线视频、网络语音电话)的场景下,可以允许偶尔的断续,但是这种协议速度快。

TCP、UDP的报文结构

UDP的报文结构:
在这里插入图片描述
TCP的报文结构
在这里插入图片描述

TCP协议三次握手、四次挥手、超时重传(?报文格式详解还未知晓!需再看)

在这里插入图片描述
三次握手是指建立TCP连接协议时,需要在客户端和服务器之间发送三个包,握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。

  1. 客户端向服务端发送⼀个SYN
  2. 服务端接收到SYN后,给客户端发送⼀个SYN_ACK
  3. 客户端接收到SYN_ACK后,再给服务端发送⼀个ACK
    在这里插入图片描述
    在断开TCP连接时,需要通过四次挥⼿来断开,过程是:
    1. 客户端向服务端发送FIN
    2. 服务端接收FIN后,向客户端发送ACK,表示我接收到了断开连接的请求,客户端你可以不发数据了, 不过服务端这边可能还有数据正在处理
    3. 服务端处理完所有数据后,向客户端发送FIN,表示服务端现在可以断开连接
    4. 客户端收到服务端的FIN,向服务端发送ACK,表示客户端也会断开连接了

超时重传指的是,发送数据包在一定的时间周期内没有收到相应的ACK,等待一定的时间,超时之后就认为这个数据包丢失,就会重新发送。这个等待时间被称为RTO.

其他博主的详细讲述(报文格式讲解)以及tcp三握四挥:
https://www.cnblogs.com/jainszhang/p/10641728.html

消息队列如何保证消息可靠传输(消息队列不够熟)

消息可靠传输代表了两层意思,既不能多也不能少。

  1. 为了保证消息不多,也就是消息不能重复,也就是⽣产者不能重复⽣产消息,或者消费者不能重复消费 消息
    a. ⾸先要确保消息不多发,这个不常出现,也⽐较难控制,因为如果出现了多发,很⼤的原因是⽣产 者⾃⼰的原因,如果要避免出现问题,就需要在消费端做控制
    b. 要避免不重复消费,最保险的机制就是消费者实现幂等性,保证就算重复消费,也不会有问题,通 过幂等性,也能解决⽣产者重复发送消息的问题
    幂等性:就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用。举个最简单的例子,那就是支付,用户购买商品后支付,支付扣款成功,但是返回结果的时候网络异常,此时钱已经扣了,用户再次点击按钮,此时会进行第二次扣款,返回结果成功,用户查询余额发现多扣钱了,流水记录也变成了两条。在以前的单应用系统中,我们只需要把数据操作放入事务中即可,发生错误立即回滚,但是再响应客户端的时候也有可能出现网络中断或者异常等等。
  2. 消息不能少,意思就是消息不能丢失,⽣产者发送的消息,消费者⼀定要能消费到,对于这个问题,就 要考虑两个⽅⾯
    a. ⽣产者发送消息时,要确认broker确实收到并持久化了这条消息,⽐如RabbitMQ的confirm机 制,Kafka的ack机制都可以保证⽣产者能正确的将消息发送给broker
    b. broker要等待消费者真正确认消费到了消息时才删除掉消息,这⾥通常就是消费端ack机制,消费 者接收到⼀条消息后,如果确认没问题了,就可以给broker发送⼀个ack,broker接收到ack后才会删除消息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值