工厂模式
一句话总结工厂模式:方便创建 同种产品类型的 复杂参数 对象
工厂模式重点就是适用于 构建同产品类型(同一个接口 基类)的不同对象时,这些对象new很复杂,需要很多的参数,而这些参数中大部分都是固定的,so,懒惰的程序员便用工厂模式封装之。
(如果构建某个对象很复杂,需要很多参数,但这些参数大部分都是“不固定”的,应该使用Builder模式)
为了适应程序的扩展性,拥抱变化,便衍生出了 普通工厂、抽象工厂等模式。
MySQL优化
Spring循环依赖怎么解决
Synchronized锁住了以后,还要加volatile吗
直接用单例模式中的双检索来举例,volatile防止指令重排,可能对象还没初始化,但是其地址以及地址引用已经准备完成,此时对象已经不为空值,此时另一个线程来调用该对象,却拿不到对象的值,因为还没初始化。
线程池核心参数,有哪些拒绝策略
ThreadPoolExecutor最核心的构造方法 :
线程池拒绝策略
拒绝策略RejectedExecutionHandler做一下详细的工作:在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会有问题,针对这些问题java线程池提供了以下几种策略:
(1)AbortPolicy
(2)DiscardPolicy
(3)DiscardOldestPolicy
(4)CallerRunsPolicy
(5)自定义
Socket通信
Socket原理讲解
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
网络层的发送的包是指什么?
在物理层传输的是一个个比特位(bit),在数据链路层中传输的是一个个以许多字节为单位的帧(Frame),在每个帧的帧头都有源节点的MAC地址和目的节点的MAC地址,局域网内部的寻址就是通过MAC地址进行的,而在网络层中传输的是数据包(Packet,也叫分组),一个数据包是一个数据帧经过网络层协议重封装后得到的,每个数据包的包头(IP头)都有源节点和目的节点的IP地址,网路间的寻址就是通过IP地址进行的。这样我们知道网络通信只有两种情况:如果通信双方在同一个局域网内,可直接通过数据链路层进行相互通信,但因为主机其实也有网络层的路由功能,所以两台主机间进行网络通信时通常也是通过三层来进行的(IP协议则是IP地址寻址);如果通信双方在不同网络内,毫无疑问必须通过三层进行。事实上,网络层的IP包到达链路层后还要重封装成帧,因为不同网络中的统一标识就是三层地址(网络IP地址,二层就是mac地址),局域网内链路层的则是MAC地址。所以不同层传输的数据包格式不一样,因为每层的标识不一样。网络层的IP包封装成帧后,其中封装的源和目的网络地址作为帧的数据部分,不会改变,这在前面的数据链路层中有介绍。
设计模式分类(创建型模式、结构型模式、行为模式)
1.创建型模式
前面讲过,社会化的分工越来越细,自然在软件设计方面也是如此,因此对象的创建和对象的使用分开也就成为了必然趋势。因为对象的创建会消耗掉系统的很多资源,所以单独对对象的创建进行研究,从而能够高效地创建对象就是创建型模式要探讨的问题。这里有6个具体的创建型模式可供研究,它们分别是:
简单工厂模式(Simple Factory)
工厂方法模式(Factory Method)
抽象工厂模式(Abstract Factory)
创建者模式(Builder)
原型模式(Prototype)
单例模式(Singleton)
说明:严格来说,简单工厂模式不是GoF总结出来的23种设计模式之一。
2.结构型模式
在解决了对象的创建问题之后,对象的组成以及对象之间的依赖关系就成了开发人员关注的焦点,因为如何设计对象的结构、继承和依赖关系会影响到后续程序的维护性、代码的健壮性、耦合性等。对象结构的设计很容易体现出设计人员水平的高低,这里有7个具体的结构型模式可供研究,它们分别是:
外观模式/门面模式(Facade门面模式)
适配器模式(Adapter)
代理模式(Proxy)
装饰模式(Decorator)
桥梁模式/桥接模式(Bridge)
组合模式(Composite)
享元模式(Flyweight)
3.行为型模式
在对象的结构和对象的创建问题都解决了之后,就剩下对象的行为问题了,如果对象的行为设计的好,那么对象的行为就会更清晰,它们之间的协作效率就会提高,这里有11个具体的行为型模式可供研究,它们分别是:
模板方法模式(Template Method)
观察者模式(Observer)
状态模式(State)
策略模式(Strategy)
职责链模式(Chain of Responsibility)
命令模式(Command)
访问者模式(Visitor)
调停者模式(Mediator)
备忘录模式(Memento)
迭代器模式(Iterator)
解释器模式(Interpreter)
TCP与UDP
UDP
UDP只在IP数据报服务的基础上增加了少量的功能:复用与分用、对整个报文的差错检测。
UDP是无连接的
通信前不需要建立连接,通信结束也无需释放连接。
UDP是不可靠的
它是尽力而为交付,不能确保每一个数据报都送达。
UDP是面向报文的
所谓『面向报文』就是指:UDP数据传输的单位是报文,且不会对数据作任何 拆分 和 拼接 操作。
在发送端,应用程序给传输层的UDP什么样的数据,UDP不会对数据进行切分,只增加一个UDP头并交给网络层。
在接收端,UDP收到网络层的数据报后,去除IP数据报头部后遍交给应用层,不会作任何拼接操作。
UDP没有拥塞控制
UDP始终以恒定的速率发送数据,并不会根据网络拥塞情况对发送速率作调整。这种方式有利有弊。
弊端:网络拥塞时有些报文可能会丢失,因此UDP不可靠。
优点:有些使用场景允许报文丢失,如:直播、语音通话,但对实时性要求很高,此时UDP还是很有用武之地的。
UDP支持一对一、一对多、多对多、多对一通信
而TCP只支持一对一通信。
UDP首部开销小,只有8字节。
而TCP头部至少由20字节,相比于TCP要高效很多。
UDP结构
源端口
目的端口
长度:整个数据报的长度
检验和:整个数据报的检验和。
TCP
TCP是面向连接的
通信前需要建立连接,通信结束需要释放连接。
TCP提供可靠交付服务
所谓『可靠』指的是:TCP发送的数据无重复、无丢失、无错误、与发送端顺序一致。
TCP是面向字节流的
所谓『面向字节流』指的是:TCP以字节为单位。虽然传输的过程中数据被划分成一个个数据报,但这只是为了方便传输,接收端最终接受到的数据将与发送端的数据一模一样。
TCP提供全双工通信
所谓『全双工通信』指的是:TCP的两端既可以作为发送端,也可以作为接收端。
一条TCP连接的两端只能有两个端点
TCP只能提供点到点的通信,而UDP可以任意方式的通信。
TCP连接 与 套接字
什么是『TCP连接』?
TCP连接是一种抽象的概念,表示一条可以通信的链路。每条TCP连接有且仅有两个端点,表示通信的双方。且双发在任意时刻都可以作为发送者和接收者。
什么是『套接字』?
**一条TCP连接的两端就是两个套接字。**套接字=IP地址: 端口号。因此,TCP连接=(套接字1,套接字2)=(IP1:端口号1,IP2:端口号2)
TCP结构
源端口 和 目的端口
传输层和网络层一大重要区别就是传输层指定了数据报发往的应用进程,因此需要端口号标识。
序号
当前TCP数据报数据部分的第一个字节的序号。我们知道,TCP是面向字节的,它会对发送的每一个字节进行编号,而且不同数据报之间是连续编号的。
由于本字段4字节,可以给[0,232-1]个字节进行编号(大约4G),而且序号循环使用,当发送完232-1个字节后,序号又从0开始。一般来说,当2^32-1个字节被发送的时候,前面的字节早就发送成功了,因此序号可以循环使用。
确认号
表示当前主机作为接收端时,期望接收的下一个字节的编号是多少。也表示,当前主机已经正确接收的最后一个字节序号+1。
数据偏移(报文长度)
它表明了数据报头部的长度。
保留字段
标识符
TCP有7种标识符,用于表示TCP报文的性质。它们只能为0或1。
URG=1 当URG字段被置1,表示本数据报的数据部分包含紧急信息,此时紧急指针有效。紧急数据一定位于当前数据包数据部分的最前面,紧急指针标明了紧急数据的尾部。如control+c:这个命令要求操作系统立即停止当前进程。此时,这条命令就会存放在数据包数据部分的开头,并由紧急指针标识命令的位置,并URG字段被置1。
ACK=1 ACK被置1后确认号字段才有效。此外,TCP规定,在连接建立后传送的所有报文段都必须把ACK置1。
PSH=1 当接收方收到PSH=1的报文后,会立即将数据交付给应用程序,而不会等到缓冲区满后再提交。一些交互式应用需要这样的功能,降低命令的响应时间。
RST=1 当该值为1时,表示当前TCP连接出现严重问题,必须要释放重连。
SYN=1 SYN在建立连接时使用。当SYN=1,ACK=0时,表示当前报文段是一个连接请求报文。当SYN=1,ACK=1时,表示当前报文段是一个同意建立连接的应答报文。
FIN=1 FIN=1表示此报文段是一个释放连接的请求报文。
接收窗口大小
该字段用于实现TCP的流量控制。它表示当前接收方的接收窗口的剩余容量,发送方收到该值后会将发送窗口调整成该值的大小。发送窗口的大小又决定了发送速率,所以接收方通过设置该值就可以控制发送放的发送速率。发送方每收到一个数据报都要调整当前的发送窗口。
检验和
用于接收端检验整个数据包在传输过程中是否出错。
紧急指针
用于标识紧急数据的尾部。
选项字段
上述字段都是每个TCP头部必须要有的,而选项字段是可选的,且长度可变,最长40字节。 最常用的选项字段为MMS:最大报文长度。
线程间通信
(volatile、synchronized、wait()、notify()、countDownLatch、CyclicBarrier、Semaphore等)
线程间通信的几种实现方式
TCP拥塞控制与流量控制
滑动窗口与流量控制
滑动窗口协议(Sliding Window Protocol),属于TCP协议的一种应用,用于网络数据传输时的流量控制,以避免拥塞的发生。该协议允许发送方在停止并等待确认前发送多个数据分组。由于发送方不必每发一个分组就停下来等待确认,因此该协议可以加速数据的传输,提高网络吞吐量。
TCP通过滑动窗口的概念来进行流量控制。设想在发送端发送数据的速度很快而接收端接收速度却很慢的情况下,为了保证数据不丢失,显然需要进行流量控制, 协调好通信双方的工作节奏。所谓滑动窗口,可以理解成接收端所能提供的缓冲区大小。TCP利用一个滑动的窗口来告诉发送端对它所发送的数据能提供多大的缓冲区。
上图为通过Wireshark抓包192.168.2.1和192.168.2.198的交互截图,可以看到有个标记Win,这个标记的含义就是接收端告诉发送端自己还有多少缓冲区可以接收数据。于是发送端就可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来。
拥塞控制与流量控制
TCP传输大块数据时,肯定需要进行数据分段,而每个分段所能携带的最大数据就是1个MSS,假设大块数据为100个MSS,那么发送方发送的方式大概有如下两种:
1、 每次发送1个,收到接收方确认后,才发送下1个;
2、 一口气发送100个,然后收到对方一起确认;
显然,方式1中,一个RTT只能处理一个包,这样的传输效率太低了。而方式2看似很美好,实际会存在两个问题,一个是接收方的接收窗口未必能一次性接收这么多数据,另外一个是网络的带宽也不一定足够大,容易出现丢包事故。前一个问题就是标题中的流量控制(Flow control),TCP采用的是滑动窗口机制(Sliding window),后一个问题就是标题中的拥塞控制(Congestion control)。
拥塞控制包括四部分:慢启动、拥塞避免、快速重传、快速恢复
发送端向网络一次连续写入的数据量,我们称为SWND(Send Window,发送窗口).但是发送端最终以TCP报文段来发送数据,所以SWND的大小限制了能连续发送的TCP报文段数量。这些TCP报文段的最大长度(仅数据部分)称为SMSS(Sender Maximum Segment Size,发送者最大段大小),其值一般等于MSS。
发送端需要合理的选择SWND的大小,如果SWND太小,会引起明显的网络延迟;反之,如果SWND太大,则容易导致网络拥塞。所以还需要引入一个称为拥塞窗口(Congestion Window,CWND)的状态变量
(1)慢启动
发送方维持一个拥塞窗口CWND的状态变量。它的大小取决于网络的拥塞程度,并且在动态的变化,发送方会让自己的发送窗口等于这个拥塞窗口。
发送方控制拥塞窗口的原则是:
(1)只要网络没有出现拥塞,拥塞窗口就再增大一些,以便把更多的分组发送出去。
(2)但只要网络出现拥塞,拥塞窗口就减小一些,以减少注入到网络中的分组数。
慢启动算法:因为不清楚网络状况,所以需要进行试探,将发送窗口逐渐增大,也就是逐渐增大拥塞窗口的数值。在刚开始发送的时候,先把拥塞窗口CWND设置为最大报文段MSS,每收到一个对新报文段的确认后,就把拥塞窗口最多增加一个MSS数值。这种逐步增大的方法可以使分组注入到网络的速率更加合理。【指数增长】
为了防止拥塞窗口过大引起网络拥塞,我们需要设置一个慢开始门限ssthreth状态变量,当cwnd < ssthreth时,使用慢开始算法;当cwnd > ssthrerth时,使用拥塞控制算法;如果两者相等,两个都可以使用。
慢启动的“慢”并不是指CWND增长速率慢而是说在TCP开始发送报文时,先设置CWND=1,使发送端开始时只发送一个报文段进行探测。
(2)拥塞避免
就是让拥塞窗口缓慢增大,即每经过一个往返时间RTT就使cwnd+1,这种线性增长的速率慢很多。
只要发送方判断出网络拥塞,不论是在慢开始还是拥塞控制阶段,都要把慢开始门限值设置为出现拥塞时发送端窗口大小的一半,但不能小于2。然后把cwnd重新置为1,执行慢开始算法。
门限值减半,cwnd重置为1,做目的是减少发送到网络中的分组数,使得发生拥塞的路由器能够有时间能把队列中积压的分组处理掉。
发送端判断网络拥塞的依据:
①传送超时,即TCP重传定时器溢出
②收到重复的确认报文
(3)快重传
快重传算法要求接收方每收到一个失序的报文段后就立即发出重复确认,而不要等到自己发送数据时才进行捎带确认。发送方只要一连收到3个同样的确认报文就应当立即重传数据报,不必等待报文段的重传计时器到期。
(4)快恢复
把慢开始门限减半,“乘法减小”,将cwnd设置为新的慢开始门限值,继续执行拥塞避免算法,“加法增大”;
进入拥塞避免之后,最终还是会碰到拥塞点,发送方此时迟迟得不到确认,当然得不到确认也有可能是因为延迟确认导致的。发送方此时决定等待一段时间,如果一段时间后还是得不到确认,就发起重传,这个过程叫做超时重传。从发出原始包到重传该包的时间叫做RTO(Retransmission TimeOut)。
进入超时重传后,RFC建议将cwnd设置为1个MSS,而对于ssthresh,RFC5681建议的是发生拥塞时未被ACK的数据量的1/2,但必须大于等于2个MSS。然后重新进入慢启动环节。超时重传因为需要等待RTO之后才能进入新的恢复环节,所以对网络性能的影响是比较大的。所以各路大神又想到了一个新的方式,看能否无需等待RTO,就发起重传,这种方式叫做快速重传。快速重传规定在收到3个及以上重复ACK时就触发重传,不再进入慢启动环节,然后直接进入拥塞避免,这个就是快速恢复算法。
SSM项目部署
数据库批量插入
1、合并SQL语句,把多条数据插入放在一条SQL语句中一次执行,减少了数据库连接的I/O开销;
2、在事务中进行插入处理,因为每进行一个INSERT操作时,MySQL内部会建立一个事务,而将所有插入语句都写到一个事务中可以减少创建事务的消耗;
3、数据有序插入,在主键上是有序排列。