Java基本知识
基本知识
服务器:Tomcat 支持Servlet jsp JBoss 开源应用服务器 Apache:最广泛的http服务器,只支持静态网页
String是长度不可变,用+=的时候会生成一个新的String对象,StringBuffer和StringBuilder是可变长度,StringBuffer为线程安全
并发编程:原子性 客观性 有序性
serializable : 静态不能被序列化,被transient修饰的也不能被序列化
面向过程和面向对象:
面向过程:速度快,效率高 难维护,难扩展 ,难服用
面向对象:速度较面向过程慢,但易维护,易扩展,易复用
jdk和jre的区别: jdk的bin下有javac jre的bin下没有
基本数据类型 double 在判断相等时,为什么不可以用==?答案:存储精度问题,一般使用阈值, a-b 小于这个阈值,一般就认为相等。
并行:两个或多个事件,在同一时刻发生。并发:两个或多个事件,在同一时间间隔发生。
Object并没有实现CallAble方法,如果在Object调用会抛出异常
子类和父类同名,会覆盖,但是可以在子类中super调用
a对应的ASCII编码为 97 A为65 0为45
如果一个局部变量没有赋初始值不可调用
进程基本状态:县城:比进程更小的独立运行单位,同一进程中可有多个线程并发执行。线程: cpu 调度基本单位。进程: cpu 分配资源基本单位。
Integer.parseInt(s,x)s代表转换的数字,x代表转换为多少进制
若try,finally都有retrun语句,则忽略try中的return
内部类
成员内部类
局部内部类
静态内部类
匿名内部类(继承一个方法或者实现一个接口)
外部类的成员不能访问内部类的成员(static内部类除外) 内部类可以访问外部类的所有成员。
端口号来区分进程
java 反射
- 可以在运行时获取类的信息
StringBuffer 底层是char[] 扩容一个扩容 2倍+2 (左移1)
常量池中只会存在一个值相同的String对象
局部变量没有默认值,必须手动赋值
Java接口的修饰符只可以是abstract和public的
Error和Exception的区别
Error 类一般指的为虚拟机的异常,对于这种异常,程序本身无法恢复和预防
Exceptio 表示程序可以处理的异常,即程序编写错误出现的异常。
Final初始化只有两个地方 定义和构造函数
输出两位数 System.out.print("%.2f",cc);
Java同步锁
每一个对象自己都带了一把锁,即monitor锁,monitor是线程私有的数据结构,每个线程都有一个可用的monitor record列表,同时还有一个全局可用的列表,每一个被锁住的对象都会和monitor关联,Monitor中有一个owner字段存放拥有改对象的线程的唯一标识,表示该锁被这个线程占有,
锁粗化:将多个加锁操作连起来形成一个范围更大的锁
Java8新特性:
允许在接口中添加一个方法 用default关键字修饰
lambda表达式
函数式接口
dateApi
可重复注解
集合
hashmap 初始化不会初始化数组,而是在put操作的时候初始化数组
TreeSet :实现compareTo方法,定义一个类,实现conparator,底层实现为红黑树
HashSet: HashCode不同 一定不是同一个元素, 相同则再比较啊equals 底层为二叉树
Collection有iterator 所以set和list有 map需要用entryset和keyset
hashSet不是线程安全
优先级队列的头是按照指定规则排序方式确定的最小元素
TreeMap根据键的自然顺序排序
hash查找的时间复杂度与原始数量无关,hash表查找元素的时候是直接通过计算hash值来确定元素的位置,从而直接访问元素,所欲hash表的插入,删除,查找都是O(1)
阻塞队列:
BlockingQueue 阻塞队列:如果进行put操作而队列中没有元素,则会阻塞put操作直到有元素
ArrayBlockingQueue 其构造函数必须带一个 int 参数,来指明其大小。其所含的对象是由 FIFO 顺序排列的。
linkedBlockingQueue: 大小不一定,若构造函数传入 int,则 BlockingQueue 有大小限制,否则大小为 Integer.MAX_VALUE,其所含的对象是由 FIFO 顺序
LinkList是Queue的实现
HashSet基于HashMap实现,允许null 不允许为重复,
Concurrenthashmap : 线程安全的HashMap,在get时候不需要加锁,put必须加锁
ConcurrentMap 允许一遍迭代一遍更新
线程
各个线程共享进程资源,也可以独立调度,线程是CPU调度的基本单位
竞态条件:
- 由于不恰当的执行顺序而产生不一样的结果,基于一种可能失效的观察结果来做出判断。
线程池的状态
刚被创建的时候处于 running状态
调用shutdown方法后,属于shutdown状态,此时不接受新的线程,等待已经有的线程任务执行完毕
调用shutdownNow方法后,进入stop状态,此时不接受新的线程,并且尝试终止正在执行的线程
当处于shutdown或者stop状态,并且所有线程已经销毁,任务缓存队列已经清空的时候,线程池进入terminated
synchronized VS lock
L是一个接口,S是一个关键字
S在发生异常的时候会自动释放对象锁,L发生异常如果没有unlock则不会释放锁,所以要将unlock放在finally中
通过L可以知道是否成功的获得锁, S不可以
L可以提高多个线程进行读写的效率
ThreadLoacl:ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。ThreadLocl采用的是hash表的方式来为每一个线程提供副本
类中有一个map,用来存储每一个线程变量的副本,map的key为Threadlocal对象,value为该变量的线程副本。
关键在ThreadLocalMap类中,他是ThreadLocal的静态内部类,它实现了键值对的设置和获取。每个线程对应一个ThreadlocalMap,从而实现了变量访问在不同线程中的隔离。因为每个线程的变量都是自己特有的,完全不会有并发错误。
公平锁
- 多个线程在等待一个锁的时候按照申请锁的顺序来分配, Synchronized为非公平锁
自旋锁
- 当两个或者两个以上的线程并行执行的时候,我们就可以让后面的线程稍微等一下,但不放弃处理器的执行时间,看看持有锁的线程是否很快就释放锁,为了让线程等待,我们需要让线程执行一个忙循环,这就是自旋锁。
Synchronized : 同步代码块和同步方法 , 同步方法对象锁是this 静态方法是所在类的class对象
synchronized关键字经过编译后,会在同步代码块的前后分别形成moniterenter和moniterexit两个字节码指令,这两个字节码参数都需要一个reference类型的参数指明要锁定和解锁的对象,在执行moniterenter指令的时候首先要尝试获取对象的锁,若这个对象还没有被锁定,或当前线程对应已经拥有那个锁对象,把锁的计数器+1,相应的在执行moniterexit时会将锁的计数器-1,当计数器为零时,锁被释放。
java虚拟机可以从方法表中acc_aynchronized标志位知道一个方法是否为同步方法,当一个方法是同步方法的时候,执行线程要求先成功持有moniter,才能执行方法
多线程的问题:当多个线程操作一个线程共享语句的时候,一个线程只执行了语句的一部分,还没有执行完,另一个线程参与执行,此时会引起共享数据的错误, 解决办法:线程同步
ReenTrantLock: 可重入锁,即现在占有这个锁的线程可以重复进入,但是必须要重复退出 ,2. 可以中断, 3. 可以设定获取锁的时间,在指定时间内没有获取到锁,则会返回失败,不会构成死锁 4. 公平锁:先来先得
共享锁:允许多个线程同时进入临界区,但是共享额度是有限的,当额度用完了 其他线程还是要阻塞, 当额度为1时相当于lock
ReadWriteLock : 读写锁,读-读不互斥,读写互斥,写-写也互斥
线程池中的线程任务就是不断检查任务队列是否有队列并且不断执行队列中的任务
Sleep Wait
Sleep是线程的方法而wait是Object类的方法,sleep只释放cpu的执行权
Sleep不释放对象锁而wait释放对象锁
Sleep在指定时间后会自动回到就绪状态,而wait需要唤醒
同步:当发出一个调用的时候,在没有得到结果以前,等待调用结果,期间当前程序阻塞
异步:调用在发出后立即返回,不等待调用结果,而是在结果出来以后被调用者通过状态通知调用者,
阻塞:当结果没有返回前当前线程会被挂起,知道等到结果返回
非阻塞:不能立刻得到结果之前,该调用不会阻塞当前线程。
BIO:同步阻塞
NIO:同步非阻塞
AIO:异步非阻塞
NIO
newIO是一个新的IO
Io:面向流、阻塞、无选择器; nio:面向缓冲,非阻塞 io,有选择器;
NIO:nio的效率比io高,nio是面对缓存,而io是直接面对流,nio是非堵塞,而io是堵塞
channel:任何来源的目的地都需要通过一个channel对象,一个Buffer是一个容器对象,发给channer的数据都需要先放到buffer中,从channel读取的数据都需要放到buffer中
使用buffer读写数据: 1. 写入数据到buffer 2. 调用filp方法 3. 从buffer中读取数据 4. 调用clear和compact方法
想buffer中写入数据的时候,buffer会记录写入了多少行,读取数据完成以后需要清空缓冲区,让他可以再次被写入,有两种方式能清空缓存区, 1. clear 清空所有缓存区 2. compact清除已经读取过的数据
channel类型
Filechannel:从文件读取数据
Datagramchannel:读写 udp 的网络协议数据。
Socketchannel:读写 tcp 网络协议数据。
Serversocketchannel:可以监听 tcp 连接。
文件读取部分需要三步:从FileInputStream获取Channer, 创建Buffer 从Buffer读取数据
public static void main(String[] args) throws IOException { FileInputStream fileInputStream = new FileInputStream(new File("Demo1.java")); FileChannel channel = fileInputStream.getChannel(); ByteBuffer buffer = ByteBuffer.allocate(1024); FileOutputStream fileOutputStream = new FileOutputStream(new File("Demo2")); FileChannel outChannel = fileOutputStream.getChannel(); int len = 0; long size = 0; while ((len = channel.read(buffer)) != -1) { size = size + len; buffer.flip(); outChannel.write(buffer); buffer.clear(); } System.out.println(size / 1024.0); fileInputStream.close(); fileOutputStream.close(); channel.close(); outChannel.close(); }
selector是一个对象,可以注册到多个channel,监听各个channel上发生的事情,并且能够根据事情来决定channel的读写,这样可以通过一个线程管理多个channel,处理大量网络连接
selector只可以管理异步的channel,socketchannel
SelectionKey key = channel2.register(selector, SelectionKey.OP_READ);
- 第二个参数:通道触发一个事件即ready 所选参数 1. 连接 connect 2. 准备好接收数据 accept 3. 数据可读 read 4. 数据可写 write 可以注册多个事件,
Int interest=SelectionKey.OP_READ|SelectionKey.OP_ACCEPT
- 第二个参数:通道触发一个事件即ready 所选参数 1. 连接 connect 2. 准备好接收数据 accept 3. 数据可读 read 4. 数据可写 write 可以注册多个事件,
当selector上注册了一个或多个通道,可以调用重载的方法返回你感兴趣的事件
selector.select(SelectionKey.OP_ACCEPT);
Int select():阻塞到至少有一个通道在你注册的事件上就绪; Int select(long timeout):与select()一样,只是最长只会阻塞 timeout ms;Int selectnow(),不阻塞,不管什么通道就绪都立即返回,若自从前一次选择操作后,没有通道变为可选的,则直接返回 0。
Web编程
Servlet声明周期,当初始化web容器或者第一次访问Servlet时会初始化Servlet,调用构造方法和init,当请求Servlet时会通过doserivice判断调用那个方法,Servlet销毁时调用destory方法
动态包含 <%@include file%> 静态包含
Cookie放在客户端
Cookie默认是会话级别的,存储在浏览器中,希望保存Cookie是需要设置Cookie的最大存活时间。
Cookie是客户端保持Http状态的解决办法, Session 是服务端保持Http状态的解决办法
Session
一个Session对应的一个SessionID
当创建一个Session时,会将SessionID放在Cookie中来传输,下次浏览器访问的时候会带上这个SessionID,浏览器就知道当前用户对应的Session(也可以通过URl来传输)
关闭浏览器只会使客户端session失效,服务端不会(但是服务端session有最大存活时间)
Filter 的应用:
禁用浏览器的缓存。
字符编码过滤器。若没有过滤器则在每一个请求页面中都要写request.setCharacterEncoding,
检测用户是否登录的 filter。
forword和redirect
是服务器请求资源,服务器直接访问目标地址的url,把url相应的内容读取出来,然后发送给浏览器,浏览器根本不知道服务器发送的内容从哪里取得,所以地址栏还是原来的地址
redirect 是让浏览器去访问地址,所以地址栏会改变,相当于两个request和response
forward 转发页面和转发到的页面可以共享数据 redirect不能
forward 只能在web应用之间转发, redirect可以定位到同一个站点上的其他资源
forward / 代表web应用根目录, Redirect / 代表栈顶根目录
jsp九大内置对象
request
session
appication
pageContext
request
out
page
config
exception
jsp动作
jsp:include :包含
jsp:userBean : 寻找或者实例化一个bean
jsp:setProperty:传递参数
jsp:forward 请求转发
如何实现 servlet 单线程模式?答案:要实现单线程模式,可以在配置文件中修改isThreadSafe 属性,比如,<%@page isThreadSafe=”false”%>
静态包含, 在编译前就将两个jsp页面包含,最后生成一个Servlet
动态包含: 先把两个jsp页面解析为Servlet 在整合
Hiberante 1+N的问题
一对多: 在1的一方查询到对象,由于关联的存在,需要将n个关联对象取出来,因为集合的数量为n还要发n条sql 所以一共发送n+1
多对一:多的一方查询到了n个对象,发出了n条语句,因为n个对象关联一个对象所以要再发送一条语句 所以为n+1
iterator:查询时会先去缓存中寻找 然后如果没有则去数据库 为n+1
Hibernate Load 和 Get区别
如果没有查询到对象,get返回null,而load抛出异常
Load返回实体的代理类,而get返回实体类
load可以利用二级缓存来查询数据,而get只能用内部缓存,如果内部缓存没有则会跳过二级缓存直接查询数据库
我们用Session.load加载一个对象时不会产生Sql语句,得到的只是一个代理对象,当用到其他字段的时候才会发送查询语句,session.get不管我们是否使用这个对象都会发送sql语句
xml
XML解析的三种方式
sax:不需要读入整个文件就可以解析出文件内容,是一种逐步解析的方法,适合大规模的解析,事件驱动,不能修改内容,顺序查询
dom:将整个文档读入内存,建立dom树,支持修改,可随机查询
digester:将xml转化为javaBean
数据库
索引添加的位置
经常需要搜索的列
作为主键的列
经常用在连接的列
经常需要进行范围搜索,索引已经排序,指定的范围是连续的
经常需要排序的列
什么情况会使得索引失效
条件中有or(若想在or中使用索引必须在全部的条件段都添加索引)
like查询以%开头
若数据类型为字符串,则需要用“”引起来否则不使用索引
mysql估计使用全表扫描比索引快
对索引进行运算
b-树 is null 会用 is not null 不会用
sql优化
尽量不要全表扫描 在where或者order by的列上添加索引
尽量避免在where子语句中有where num is null 这样会进行全表扫描
避免在where中用or 若一个字段有索引,另一个没有 则会全表
避免在where <>or != 全表扫描
使用复合索引的时候需要,必须用到改索引的第一个字段
索引的缺点:
创建和维护索引要耗费时间。
索引需要占用物理空间,除了数据表占数据空间以外,每一个索引还要占物理空间。
当对表中数据进行增加、删除和修改时,索引也要动态维护,这样就降低了数据的维护速度
Redis是一个Nosql数据库,高并发,高性能,面向Key-value
数据库的范式:
第一范式:强调列的原子性,列不能再分为其他几列,属性不可分。
首先是 1NF,另外包含两个部分, 1)一个表必须有主键 2)没有包含在主键中的列必须完全依赖于主键,而不能只依赖于主键的一部分
首先是 2NF,非主键列必须直接依赖于主键,不能存在传递依赖,即不能存在非主键 A 依赖于非主键 b,非主键 b 依赖于主键的情况,消除传递依赖
乐观锁和悲观锁:
悲观所: 每次别人拿数据的时候都会认为别人会修改这个数据,所以每次在使用数据的时候都会对数据上锁,这样别人想使用这个数据就会Block知道它拿到锁,传统的关系型数据库用到了很多,比如行锁,写锁。都是在操作之前上锁
乐观锁: 乐观的以为每次使用数据的时候别人都不会修改数据,所以不会上锁,当别人在更新数据的时候会判断一下再次期间有没有别人更新这个数据,具体实现的方式为,为每个表增加一个字段,表示版本号,当更新的时候判断需要更新的版本号和数据库中版本号,如果大于,则更新,若小于则不更新。
数据库的排它锁和共享锁
共享锁(读锁):当一个事务对一个对象上了共享锁,其他事务只能对这个对象加共享锁,只能读取,不能修改
排它锁(写锁):如果事务T对数据A加上排他锁后,则其他事务不能再对A加任任何类型的封锁。获准排他锁的事务既能读数据,又能修改数据。
mysql怎么判断是否使用了索引,可以在select 前面添加关键字eaplain 返回的数据中key为名字的那列为null 则没有使用索引 强制使用索引select * from tablename from index(index_name);
sql:
Select * from tablename orderby liename limit m,n (从 m+1 条开始,取 n 条数据)。
Select a.,b. from a inner join b on a.id=b. parent_id; 内连接
Select a.,b.from a left join b on a.id=b. parent_id; 左外连接,左表的全部元素都有
Select a.,b.from a right join b on a.id=b. parent_id; 右外连接,右表的全部元素都有
Select a.,b.from a full join b on a.id=b. parent_id;
- 完全连接返回左边和右表中所有行,若某行在另外一个表中无匹配,则另一表的选择列表列包含空值)
sql不等于<>
设计模式
代理设计模式
- 代理类和委托类有相同的接口,代理类的对象本身并不实现具体的服务,而是通过调用委托类中具体的方法来提供特定的服务。
如果理解代理和装饰, 代理类可以对他的用户隐藏一个对象的具体信息,所以代理是在内部生成一个代理对象,构造函数为空,装饰的构造函数的参数为一个对象,就是对这个传递进来的对象进行装饰
观察者模式
当被观察者的行为状态发生改变的时候会通知观察者来进行相应的操作(老鼠和猫, 过马路都是, 监听器)
一个对象的改变需要通知其他的对象。
java实现方式:观察者实现统一的接口,然后将观察者添加到被观察者类中的一个集合,当观察者某个状态改变的时候会遍历集合中的放啊并且调用对应的方法 (Observer 接口 Observable 类)
工厂模式
- 出现了大量的产品需要创建,并且实现了相同的接口,可以通过工厂方法模式进行创建,一个工厂里,不同方法创建不同的类,根据传入进去的参数不同产生不同的类。
抽象工厂模式
- 创建工厂的工厂,在扩展程序的时候无需修改工厂类,直接通过抽象工厂模式创建一个新的工厂类,增强了程序的扩展性。
建造者模式
- 工厂模式提供的是创建单个对象的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象。
原型模式
- 该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象,适用于产生一个新对象所需要的代价比较大的情况, 浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。
订阅-发布模式
- 观察者模式中观察者是由被观察者触发调用的,而订阅发布模式是由调度中心来调度,所以观察者模式会存在依赖,这个就不会
适配器模式
将某个类的接口转换为客户希望的接口,是两个不相容接口之间的桥梁,结合了两个独立的接口的功能。
类的适配器:当希望讲一个类转换为满足一个接口类的时候可以集成这个类并且实现这个接口
接口的适配:当我们只是希望实现一个接口中的某些方法的时候可以先用一个抽象类实现接口中的方法,然后我们继承这个抽象类实现我们所想实现的方法就可以
对象的适配:希望将一个对象转换为满足一个新接口的对象,创建一个wapper类,包含原来类和新接口,调用原类的实例的方法
外观模式
- 解决类和类之间的依赖关系,将他们的关系放在一个facede类中,改模式没有涉及到接口, 将几个向关联的类放在一个类中,在类中编写逻辑调用方法。
桥接模式:把事物和具体的实现分开,使他们可以独自变化 jdbc
设计模式在JAVA中的应用
- 单例模式 Runtime
- 静态工厂 :Integer.valueOf
- 迭代器模式:in
- 原型设计 clone
- 适配器模式 inputStreamReader
- 桥接模式 jdbc
- 装饰模式:Reader和BufferREader
- Drivermanager.getConnection
JVM
若有一个类加载请求,先检查是否已经被加载,如果没有被加载,则调用父类加载器的loadclass方法,若父类加载器为空,则默认使用启动类加载器作为父类加载器,若父类加载器失败,抛出异常,再调用自己的findclass方法进行加载
类的初始化顺序:加载class文件,静态变量初始化(子类和父类 执行的为出现顺序) 父类的变量,父类构造代码块,父类构造器,子类变量,子类构造代码块,子类构造函数
Java编译的过程
解析和填充符号表的过程
注解处理
分析与生成字节码过程
JVM启动加载类的时候
运行bootstarp classLoader 加载核心api,然后执行ext classloader加载扩展的API,最后app classloader 加载classpath目录下的class,最基本的流程。
通过classloader加载类的时候不会对类进行解析,也不会初始化, forName方法会解析和初始化class
JVM参数
Xmx:最大堆大小
Xms: 最小堆大小
Xmn: 年轻代堆大小
Xss: 堆的大小
XXSurvivoRatio: 年轻代中eden和survivo区的大小比较
类的加载过程
加载
通过全类名获取二进制流
将字节流表示的静态存储结构转换为方法区的运行时数据结构
生成class文件
验证
- 保证class文件的字节流中包含的信息是否符合当前虚拟机的要求
准备
- 为变量分配内存,并设置变量的初始值
解析
- 将常量池中的符号引用变为直接引用
初始化 : 初始化这个类,如果这个类有父类先初始化父类。
类加载器:
启动类加载器 lib
扩展类加载器 lib/ext
应用程序类加载器 加载classpath 的class
内存泄露,对象是可达的,对象以后不会被用到
内存溢出(程序申请内存时没有足够的内存分配)
java虚拟机操作码只有一个字节
符号引用的目标不一定加入内存,直接引用的目标一定加入了内存
垃圾回收
GCRoot : 通过一系列的GCRoot对象作为起始点,从这些节点开始向下搜索,走过的路径为引用链,当一个对象到GcRoot没有一个引用链,则该回收,若对象没有引用链相连接,那么它会被标记和进行一次筛选,若对象乜有重写finalize方法或者已经被调用,则会被销毁,如果有必要执行finalize方法,则会将该对象放入F-Queue队列,会进行第二次标记,如果他们在此期间与一个对象向连接,则不会被回收
GCRoot:
Java虚拟机栈中引用的对象
方法区中类的静态属性引用的对象
方法区中常量引用的对象
本地方法栈JNI引用的对象(JNI 调用其他的语言 如C,C++ 使用方式 native)
停止-复制算法:
- 将内存分为相等的两块 每次使用其中的一块,回收垃圾时将这一块上存活的对象放到另一块上面,然后清理这一块(效率不高,产生内存碎片)
分带收集
分为年轻带(Eden,Survivo1,Survivo2),老年代(Tenured)
一开始对象都放在Eden区域,当新对象生成并且Eden申请空间失败时,会触发minor gc,对Eden区域进行GC,清除非存活对象,并且把存活的对象都移动到Survivo1内,然后整理Survivo两个内存区,在这里进行的GC不会影响到老年代,所以Eden区的GC会频繁进行。因而,一般在这里需要使用速度快、效率高的算法,使Eden区能尽快空闲出来。同时每个对象都有一个年龄,就是经历过minor gc的次数,当一个对象的年龄到了一定的限制的时候会把这个对象移动到老年区,当老年区的空间没有的时候就会触发老年区的的垃圾回收处理
垃圾回收常用的分配方式:指针碰撞,空闲列表
Class文件的内容
每个class文件的前4个自己为标识是否能被虚拟机接受
接着为版本号(5 6 字节为次版本号 7 8 为主版本)
接着主版本号的为常量池的入口
访问标志
索引(类索引,父类索引,接口索引)
字段表
方法表
属性表
网络编程
tcp如何保证可靠性
将数据分割为tcp认为适合发送的数据块
超时重传:当tcp发出一个数据段后,会启动一个定时器,等待目的端确认收取这个报文,在一定时间内若不能及时收到一个确认,则会重新发送一个报文段。
当tcp收到一个报文段的时候会给对方发送一个确定,这个确认通常不是立即发送,通常推迟几分之1秒
当tcp收到报文段但报文段有错误的时候将会丢弃报文段,并且不给出响应
对于失序的数据进行重新排序然后交给应用层
对于重复的数据,直接丢弃
tcp可以进行流量的控制,防止主机较快的一方传输数据过快导致主机较慢的一方缓存区溢出
字节流服务
- 两个应用程序通过字节流相连接,tcp不在字节流中插入记录标识符
TCP 和 UDP——tcp:面向连接,提供可靠的服务,无重复、无丢失、无差错,面向字节流,只能是点对点,首部 20 字节,全双工。 UDP:无连接,尽最大努力交付,面向报文,支持一对一、一对多、多对多,首部 8 字节
https: http+ssl/tls,在http上又添加了一层处理加密信息的模块,服务端和客户端的传输都会进行加密。
客户端发出https请求
服务端配置
传输证书
客户端解析证书(生成一个随机值并且用公钥对其加密)
传输加密信息(传输的为加密后的随机值)
服务端解密信息(用对称加密的算法解析传递过来的请求)
传输加密的相应
客户端解密(客户端抓包为明文)
反向代理和正向代理
正向代理:连接一个代理服务器让他帮助我们访问目标网站,目标网站并不知道Client是谁,
访问访问不了的网站
可以加速访问资源
对外隐藏客户信息
反向代理:客户端请求Server的时候不知道Server返回的数据从什么地方来的,代理将请求分发到不同的服务器上
负载均衡
保证内网安全
nginx设置反向代理的五种方法
轮询(默认),每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器 down 掉,能自动剔除;
指定权重,指定轮询几率。权重越大,轮询几率越大,用于后端服务器性能不均的情况。
ip 绑定 ip_path,每个请求按访问 ip 的哈希结果分配,这样每个客户固定访问一个服务器,可以解决 session 问题。
fair(第三方)按后端服务器的响应时间来分配请求,响应时间短的优先分配。
url_hash 按访问的 url 结果来分配请求,使每个 url 定位到同一个后端服务器。
webService:是一种跨编程语言和跨操作系统的远程调用技术,就是说服务器采用java编写,客户端程序可以采用其他编程语言编写,且客户端和服务器程序可以在不同操作系统上运行。
算法和数据结构
堆排序的空间复杂度(O(1)建堆的时间复杂度(O(n)) 调整堆的时间复杂度(O(logn))
哈弗曼树有左右子树之分
稀疏矩阵,三元组存储: 非零元素所在的行以及所在的列和他的值构成一个三元组,然后按照某种顺序存放三元组,还需三个变量来记录表矩阵额行数,列数和总的元素数量
BFS:广度优先遍历,使用队列
DFS:深度优先遍历,使用栈
快速排序在无序是效率高,有序时效率低
知道中序,再知道前序或者后序一个就可以构建一个二叉树
对冒泡排序的改进是加入一个标志位,标志这一次排序是否有数据交换,如果进行某一趟没有数据交换,代表已经排好序