Java八股整合(Java+JVM+操作系统+计网+数据结构)

Java基础

JDK(java开发工具包)= JRE(java运行环境) + java开发工具

JRE = JVM(java虚拟机) + java核心类库

编译型和解释型语言

编译型直接编译为机器码,解释型需要逐句解释为机器码

Java先编译成.class文件,再解释为机器码

Java与C++区别

Java 不提供指针来直接访问内存,程序内存更加安全

Java 的类是单继承的,C++ 支持多继承;虽然 Java 的类不可以多继承,但是接口可以多继承。

Java 有自动内存管理垃圾回收机制(GC),不需要程序员手动释放无用内存。

C ++同时支持方法重载和操作符重载,但是 Java 只支持方法重载(操作符重载增加了复杂性,这与 Java 最初的设计思想不符)。

基本数据类型和包装类区别

用途:基本数据类型用于常量和局部变量,包装类用于方法参数和对象属性,还可以用于泛型

存储方式:基本数据类型,局部变量放在栈中的局部变量表中;非静态成员变量放在堆中

                包装类属于对象,放在堆中

占用空间:基本类型小

默认值:包装类默认null,基本数据类型有固定默认值

比较方式:==比较包装类内存地址,比较基本数据类型值;相互比较则使用equals

包装类缓存机制

整型会缓存-128到127的值,调用时直接从缓存区调用;Character会缓存0到127的数据

自动装箱与拆箱

装箱使用valueOf方法,拆箱使用xxxValue方法

浮点数精度丢失

浮点数二进制存储不断乘以2,取整数部分,直到不存在小数部分位置,无法乘尽则截断

成员变量和局部变量区别

语法形式:成员变量属于类,局部变量在代码块或方法中

                成员变量可以被访问修饰符和静态修饰符修饰;局部变量不行。但都能被final修饰

存储方式:static成员变量属于类,非static成员变量属于对象在堆中;局部变量在栈中

生存时间:成员变量与类一起,局部变量与方法调用一起

默认值:成员变量会赋默认值(需要有指向),局部变量不会

静态变量

只分配一次内存,被所有对象共享,一般加final变为常量

重载和重写区别

重载发生在同一个类或子父类中,方法名必须相同,参数必须不同,返回值和访问修饰符可以不同,编译阶段

重写发生在子父类中,方法名和参数列表必须相同,返回值类型需要是父类方法返回值一致或子类,异常范围小于等于父类,访问修饰符范围大于等于父类,运行阶段

构造方法无法重写

创建对象过程

new对象,在堆中存储实例,在栈中存储引用,对象可以指向0或1个对象,可以被一个或多个引用指向

构造方法

与类名相同,不可重写但可重载,不能声明void,创建对象时自动调用

接口和抽象类

都不能实例化,都可以包含抽象方法,都可以有默认实现方法

接口用于规范行为,抽象类用于代码服用;单继承但是可以实现多个接口;接口成员变量必须是public static final;抽象类成员变量默认default

引用拷贝,浅拷贝和深拷贝

浅拷贝会在堆中新建对象,对象属性为引用类型时,直接复制引用地址

深拷贝完全复制对象

引用拷贝仅建立新的对象引用指向原有对象

Object类方法

getClass返回运行时的Class对象

hashcode获取对象hashcode

equals比较内存地址是否相等

clone返回当前对象的拷贝

toString返回类名16进制字符串

notify唤醒此对象监视器上等待线程

notifyAll唤醒所有线程

wait(timeout)暂停线程并等待时间

wait(timeout,naos)暂停线程并等待时间,加了额外时间

wait()暂停线程,没有等待时间,会一直暂停

finalize实例被垃圾回收器回收时调用

==和equals区别

==比较内存地址,equal重写后比较对象内容

hashcode作用

确定对象在哈希表中索引位置

对象加入hashset时会先比较hashcode,如果相同则通过equals比较是否相同,若相同则不会插入,提升处理效率

为什么重写equals需要重写hashcode

会导致equals相等但hashcode不相等

String,StringBuffer和StringBuilder

String对象不可变,StringBuffer加了Synchronized线程安全,StringBuilder线程不安全

String变量更新是在常量池中创建新的字符串并更改指向,StringBuffer变量更新是在原有字符串上更新

String为什么不可变

因为保存字符串的数组是私有且final,并且不提供外部修改数组的方法;并且String为final,防止子类继承破坏不可变性

字符串拼接用+还是StringBuilder

+本质使用了重载,底层调用StringBuilder的append方法,多次拼接会创建多个StringBuilder对象,消耗内存。JDK9中进行了优化

new (字符串)创建了几个对象

常量池中有字符串对象引用则只创建一个,没有则创建两个

String.intern方法

在常量池中查找是否有指定的字符串对象的引用,有的话则返回,没有的话创建一个返回

Exception和Error区别

Exception程序可处理,Error会直接报错退出

Checked Exception和Unchecked Exception区别

Checked Exception需要编译处理

Throwable常用方法

getMessage返回简要信息

toString返回详细信息

getLocalizedMessage返回异常对象本地化信息

printStackTrace打印对象封装异常信息

什么时候finally中语句不会执行

JVM被异常终止,程序所在线程死亡,关闭CPU

异常使用注意事项

不要把异常定义为静态变量会导致异常抛出错误,需要手动new抛出

异常信息要有意义,尽量抛出异常子类

避免重复日志记录

泛型

用于检查传入数据类型

泛型类:类名<标识符>,实例化时传入即可

泛型接口实现时可以指定或不指定泛型,在接口声明处指定

泛型方法:在返回值前加<标识符>,形参声明中加标识符

泛型实用案例

自定义通用接口返回不同结果

处理excel表格数据

构建集合工具类Collections

反射

通过反射可以获取类的所有属性和方法

会无视泛型安全检查

注解

可用于修饰类,方法,变量

本质是一个继承了annotation的特殊接口

可以通过编译时扫描或运行时通过反射处理

transient

防止变量被序列化,反序列化后恢复为默认值。static不属于对象,不会被序列化

常见的序列化协议

JSON和XML性能较差,一般使用二进制序列化协议

JDK自带序列化协议不支持跨语言调用,性能差,存在安全问题

为什么要分字节流和字符流

字符流是虚拟机转化来,消耗性能,并且不知道编码方式容易乱码

集合

List有序可重复

Set无需不可重复

Queue队列

Map用k-v存储

ArrayList底层是Object数组

Vector底层是Object数组

LinkedList底层是双向链表

HashSet底层是HashMap

LinkedHashSet底层是LinkedHashMap,链表加哈希表,取出满足FIFO

TreeSet底层是红黑树

PriorityQueue底层是Object数组

DelayQueue底层是PriorityQueue

HashMap底层是数组+链表

ArrayList和Array区别

ArrayList动态数组,可以灵活调整长度,不用创建时指定长度,可以用泛型检查,只能存储对象,可以动态插入删除遍历数据

LinkedArrayList和ArrayList区别

ArrayList尾部插入O(1)

LinkedArrayList随机插入O(n)

一般不用LinkedArrayList

Queue和Deque区别

Queue单端队列,Deque双端队列

HashMap和Hashtable区别

Hashtable线程安全,效率低,不支持null,初始大小默认11,之后每次扩容到2n+1;给定大小则为指定大小。指定使用hashcode作为键

HashMap初始大小默认16,之后每次扩容到2倍;给定大小会自动扩容到2的幂次方大小。链表长达大于8,数组大于64则会转换为红黑树,否则先扩容。哈希值采用高位地位混合扰动减少冲突

HashMap和TreeMap区别

TreeMap实现了NavigableMap接口和SortedMap接口

NavigableMap接口提供了集合内元素搜索能力

SortedMap接口提供了根据键排序的能力

HashSet查重

对象加入hashset时会先比较hashcode,如果相同则通过equals比较是否相同,若相同则不会插入,提升处理效率

HashMap长度为什么是2的幂次方

hashcode太大,需要取模,取余%操作如果除数是2的幂次则等同于与其除数减一的与操作,并且采用二进制位操作&相对于%能够提高运算效率

HashMap为什么线程不安全

会有键值覆盖覆盖的风险

ConcurrentHashMap如何实现线程安全 

JDK1.7将桶数组分块,分别加锁,访问不同块的数据不会冲突。segment继承了Reentranlock,扮演锁的角色。每个segment守护一个HashEntry数组里的元素,每个HashEntry数组属于链表结构,修改元素时必须先获取锁。

JDK1.8使用Node数组+链表+红黑树实现,并发控制通过Synchronized和CAS。红黑树使用TreeNode,通过TreeBin包装,用waiter属性维护当前这棵红黑树线程。锁粒度更细,Synchronized只锁定当前链表或红黑树首节点,只要不产生hashcode,就不会发生并发

区别:实现方式不同,碰撞解决方法不同,JDK1.7使用拉链法,JDK1.8采用拉链法结合红黑树;并发度不同,JDK1.7最多为segment数组大小,默认16,JDK1.8最大并发度是Node数组大小,并发度更大

key和value不能有null,防止分不清是原本就是null,还是未找到返回的null(二义性)

如何保证ConcurrentHashMap复合操作原子性

提供了原子性的复合操作

什么是进程

程序的一次执行过程,是系统运行程序的最小单位

什么是线程

是操作系统资源调度的最小单位,同一进程的线程共享进程中堆和方法区的资源

每个线程有自己的程序计数器,虚拟机栈和本地方法栈

java程序的运行实际上是main线程和多个其他线程同时运行

为什么要分进程和线程

进程大,调度消耗大,可以多线程执行,多个线程可以共享资源

Java线程和操作系统线程区别

jdk1.2以前,Java使用自带的用户级别线程,绿色线程,使用JVM模拟了多线程,不能使用操作系统提供的功能,比如无法异步IO,无法使用多核

jdk1.2以后基于原生线程实现

如何创建线程

实现Runnable接口,继承Thread类,实现Callable接口,线程池方法,使用ComplatableFuture类。这些是在Java中实现多线程的方法

唯一创建线程的方法是start()

线程生命周期

初始,运行,阻塞,等待,超时等待,终止

线程上下文切换

线程退出CPU,可能是调用了wait或sleep;时间片用完;调用阻塞类型系统中断;被终止或结束运行

sleep和wait区别

都可以暂停线程运行

sleep不释放锁;用于暂停线程执行;会自动苏醒;Thread中静态本地方法

wait释放锁;用于线程间交互通信;不会自动苏醒,需要notify;Object中本地方法

为什么wait不定义在Thread中

线程获取的是对象锁,每个对象都有对象锁,所以需要在对象中操作

而sleep仅让线程暂停执行,不需要释放锁

可以直接调用Thread中的run方法吗

通过start方法调用本地start0方法,再调用run方法才是多线程工作,否则只是普通方法

并发和并行区别

并发是多个线程在同一个时间段内执行,并行是多个线程在同一时刻执行

同步和异步区别

同步需要等待调用结果返回才能继续执行

为什么用多线程

1.线程是系统调度的最小单位,而现在计算机都是多核,可以同时处理多个线程,效率更高

2.多线程是高并发的基础

单核CPU可以多线程吗

可以通过时间分片实现。可以通过操作系统抢占式分配,会有上下文切换开销,也可以线程执行完毕通知其他线程,公平性差。Java是抢占式,高优先级分得时间片概率更高

单核CPU使用多线程效率一定高吗

CPU密集型任务需要CPU大量计算,使用多线程会频繁上下文切换,增大开销

IO密集型任务主要是频繁进行输入输出,使用多线程能提升效率

多线程问题

内存泄漏,死锁,线程不安全

什么是线程安全

同一份数据,多个线程同时访问都能保证数据的正确性和一致性,不会发生数据混乱,错误或丢失

死锁特征

互斥,无抢占,持有并等待,循环等待

如何检测死锁

资源分配图

使用jmap,jstack等命令查看JVM线程栈和堆的情况,出现死锁会报Found one Java-level deadlock:实际项目中还可以搭配使用topdffree等命令查看操作系统的基本情况,出现死锁可能会导致 CPU、内存等资源消耗过高。

还可以使用VisualVM、JConsole 等工具进行排查。

如何预防死锁

破坏互斥会导致无法预测线程执行结果

破坏持有并等待,一次性申请所有资源

破坏无抢占,申请不到所需资源则释放自己拥有的资源

破坏循环等待,按某一顺序申请资源(资源分级),顺序申请,逆序释放

如何避免死锁

银行家算法

如何解除死锁

结束所有线程,重启操作系统;撤销涉及死锁的进程;逐个撤销涉及死锁的进程;抢占资源

volatile

声明变量为volatile,标记为共享且不稳定变量,每次使用都到主存中读取(禁用CPU缓存)

volatile能保证数据可见性,但不能保证原子性。Synchronized两个都能保证

还可以防止JVM进行指令重排序,在对volatile标记的变量读写时会插入内存屏障

防止指令重排序

不保证原子性

悲观锁

共享资源每次只给一个线程使用,如Synchronized和Reentrantlock

高并发的场景下,激烈的锁竞争会造成线程阻塞,大量阻塞线程会导致系统的上下文切换,增加系统的性能开销。并且,悲观锁还可能会存在死锁问题,影响代码的正常运行。

用于多写多冲突情景

乐观锁

只在提交修改时验证是否被其他线程修改

冲突频繁时会频繁失败

用于多读少冲突情景

乐观锁实现

使用版本号或者CAS算法

版本号每次修改则+1,提交时版本号一致才会提交

CAS算法

依赖CPU底层的一个原子操作,V为更新的变量值,E是预期值,N是拟写入的新值

V=E时则用N更新V的值,不等则放弃更新

多个线程竞争只会有一个胜出

Java实现CAS,使用Unsafe类中的native的CAS方法

底层使用C++内联汇编实现,具体实现和操作系统及CPU都有关系,常与while结合使用,自旋锁

ABA

原来是A被修改为B又改回A,检查的时候还是A,实际已经被修改过了

解决方案是在变量前面加版本号或时间戳

自旋锁开销大

只能保证一个变量原子操作

JDK1.5以后提供了AutomicReference类,将多个变量封装在一个对象中执行CAS操作

或者加锁

Synchronized

使用方法

加在代码块或者(静态、非静态)方法上,同一时间只能有一个被执行

成员方法上需要获取对象,静态方法上需要获取class,代码块中是对象则获取对象,是静态(class)是加在class上

不能加在构造方法外部,只能加在内部。构造方法本身线程安全,但内部如果使用共享资源则需要加锁

发展历史

最初是重量级锁,JDK6以后引入了自旋锁,锁清除,锁粗化,偏向锁,轻量级锁等减少锁开销

JDK15以后偏向锁被默认关闭,JDK18以后废弃偏向锁

底层实现

修饰代码块使用monitorenter和monitorexit,分别指向同步代码块的开始和结束位置

执行monitorenter时尝试获取对象的监视器

修饰方法使用ACC_SYNCHRONIZED标识,本质也是获取对象监视器

Volatile和Synchronized区别

v只能加在变量上,保证变量在多个线程中的可见性,s加在方法和代码块上,解决访问资源同步性

v保证可见性不保证原子性,s两个都能保证

Reentrantlock(可重入锁,公平锁)

可重入(同一线程可以多次获取到已获取的锁)独占式锁,内部有Sync类,继承AQS,添加和释放锁大部分操作在内部类完成,该类有公平锁和非公平锁两个子类,默认使用非公平锁

公平锁先申请先用(FIFO),非公平锁随机或优先级排序,可能导致饥饿

Synchronized和Reentrantlock区别

都是可重入锁

s依赖于JVM,r依赖于API(需要lock和unlock配合try finally实现)

r增加了等待可中断(中断等待锁的线程),可实现公平锁(通过构造方法传入true)

r可以实现选择性通知

可中断锁和不可中断锁

r可以在等待获取锁的过程中中断,s不可中断

ReentrantReadWriteLock

读读不互斥,适合多读少写场景

有读锁不能获取写锁,有写锁可以获取读锁

读不能升级为写,写可以降级为读,升级可能会产生死锁

共享锁和独占锁

StampedLock(不重要)

ThreadLocal

让每个线程有自己的变量,创建了该类变量则每个线程都在本地有一个副本

原理

底层使用ThreadLocalMap(放变量),在调用ThreadLocal类的set方法时才创建

ThreadLocal只是对ThreadLocalMap进行了包装,map中以每个ThreadLocal为key,object为value

内存泄漏

key中ThreadLocal是弱引用,value是强引用,垃圾回收时会回收key,但不会回收value

使用set,get和remove时会清理掉key为null的value

线程池

管理线程的资源池,提供了限制和管理资源的方式,同时维护基本统计信息

降低资源消耗(线程重用),提高响应速度(不需要等待线程创建就可以执行),提高线程可管理性

核心线程即便空闲时也不回收,可以设置参数回收

线程池创建

1.使用ThreadPoolExecutor构造函数创建

2.通过Executor框架的工具类Executors创建

为什么不用内置线程池(通过第一种方法创建)

明确线程池运行规则,规避资源耗尽的风险

常用参数

线程池拒绝策略

Abort抛出异常(默认),CallerRuns返回给调用者运行,Discard丢弃任务,DiscardOldest丢弃最早的任务

CallerRuns如果返回时间长的任务,并且处理任务的是主线程,可能导致主线程阻塞,严重会导致OOM

暂时无法处理的任务可以先放在阻塞队列中(满了才会触发拒绝),还可以调整线程池最大线程数,避免阻塞队列中任务过多

任务持久化

1.设计任务表存在MySQL中

2.Redis缓存任务

3.将任务提交到消息队列中

常用阻塞队列

有界阻塞队列:最大数量为核心线程数或1,任务队列永远不满

同步队列:没有容量,不存储元素,有空闲线程就给空闲线程处理,没有空闲就创建新的线程,线程数无线扩展,可能导致OOM

延迟队列:内部元素不是按照放入的时间排序,而是按照延迟的时间长短对任务排序,内部使用堆,保证每次出队都是执行时间最靠前的

(另一个)有界阻塞队列:底层使用数组,容量确定则不能改变

处理任务流程

线程异常

execute提交任务:异常则终止并记录日志,创建新的线程代替

submit提交任务:异常封装并返回,get可以返回异常,线程不终止

线程池命名

通过guava的ThreadFactoryBuilder或自己实现ThreadFactory

线程池大小

CPU密集型任务线程池大小为N+1,N为CPU数量

IO密集型任务线程池大小为2N

修改线程池参数

主要修改核心线程数,最大线程数,阻塞队列大小

设计优先级线程池

使用优先级阻塞队列,传入的任务需要可比较,可以重写Comparable接口并重写compare方法,或传入Comparator对象

问题:OOM,饥饿,排序降低性能

Future类

用于异步处理

功能

取消任务,判断任务是否取消,判断任务是否完成,获取执行结果

Callable和Future关系(FutureTask)

FutureTask封装了Future接口的简单实现,用来峰封装Runnable和Callable

FutureTask构造器可以传入Runnable或Callable,传入Runnable会内部封装成Callable

AQS

抽象队列同步器,用来构建锁和同步器

如果请求的共享资源空闲,则请求的线程变为有效的工作线程,资源被锁定;

如果请求的资源被占用,则用CLH队列锁实现AQS机制(获取不到锁的线程加入等待队列中)

AQS内部通过int成员变量state表示同步状态,由volatile修饰通过内置线程等待队列完成排序

CLH队列锁

虚拟双向队列,不存在实例,仅存在节点之间的链接,每个线程封装成一个结点,节点保存了线程引用,节点状态,前驱,后继

信号量Semaphore

可以多个线程访问相同资源,公平模式?非公平模式

用于限流

减少计数CountDownLatch

允许count个线程被阻塞,直到所有线程任务执行完毕

计数器的值只能在构造器中初始化一次,之后无法修改

设置AQS中的state=信号量

循环屏障CyclicBarrier

基于Reentrantlock,当一组线程中所有线程都到达才会继续工作

BIO同步阻塞IO模型

read调用时阻塞,直到内核将数据完全拷贝到用户空间才会停止阻塞,效率低

NIO同步非阻塞IO模型

使用select调用,查看内核数据是否加载完成,准备完成后用户线程再发起read调用

有一个选择器selector多路复用器,管理多个客户端连接

Buffer缓冲区,读写输入发送给客户端,包含容量,界限(读写),位置,标记。逐级减小

Channel通道,指和数据源的连接,

Selector选择器,所有的Channel都可以注册到Selector上,由Selector分配线程处理

AIO(改进版NIO)

基于事件和回调机制实现,应用操作完直接返回不会阻塞,后台处理完成操作系统通知对应线程

JVM

内存模型

程序计数器(线程私有)

记录当前线程执行到的字节码位置,控制代码执行流程,顺序执行或者上下文切换记录位置

唯一一个不会出现OOM的区域

Java虚拟机栈

除了native方法通过本地方法栈实现,其他方法调用时入栈,执行完毕出栈

局部变量表存储局部变量,操作数栈存储中间结果,动态链接用于连接其他方法,将符号引用转换为直接引用

Java返回可以是返回结果或抛出异常

栈大小不能动态扩展,栈深度超出则会SOF

栈大小可以动态扩展,但是内存不足则会OOM

本地方法栈

登记native方法,最终执行时,通过JNI加载本地方法库中的方法

唯一作用就是存放对象实例

逃逸分析:如果对象引用未被返回或被外部使用则可以在栈中分配内存

Java7以前分为新生代,老年代,永久代

Java8以后永久代变为元空间,使用本地内存。永久代收JVM固定存储空间影响,同时可以加载更多类,方便合并HotSpot和JRockit代码,减少GC永久代复杂度

伊甸区一次未被回收进入幸存者0区或一区,15次以后进入老年区(设置不能超过15)

方法区

静态变量、常量、类信息 (构造方法、接口定义)、运行时的常量池存在方法区中

存储已被虚拟机加载的 类信息、字段信息、方法信息、常量、静态变量、即时编译器编译后的代码缓存等数据

方法区存储:static,final,Class,运行时常量池(用于存放Class文件编译期生成的各种字面量(Literal)和符号引用(Symbolic Reference)的 常量池表(Constant Pool Table) 。)

字符串常量池

避免字符串重复创建

在堆中分配内存

对象创建过程

类加载检查;分配内存(指针碰撞(无内存碎片),空闲列表(有内存碎片));初始化零值;设置对象头;执行Init方法

对象内存布局

对象头(标记字段,类型指针),对象体,对象填充

内存回收原则

较大连续内存地址的对象直接进入老年代

长期存活的对象进入老年代

年轻GC和老年GC,当平均年轻代晋升内存大于老年代剩余内存改为老年GC

死亡对象判断方法

引用计数法:被引用+1,引用结束-1,但是难以解决循环引用问题

可达性分析算法:从GCboot开始向下搜索,不可达对象为死亡对象

废弃常量:无人引用

无用类:无该类实例,该类加载器已被回收,对应的Class对象无任何引用且无法通过反射调用其方法

强引用,弱引用,软引用,虚引用

强引用只要指向了对象就不会被回收;弱引用只要触发GC一定被回收,软引用内存不足时回收,虚引用不决定对象生命周期,必须和引用队列一起使用

垃圾清除算法

标记清除算法,复制算法,标记整理算法,分代收集算法

类加载器

加载Java类的class字节码文件到JVM中(动态加载,只加载需要的类)

启动类加载器(无法获取class,因为是c++加载的),扩展类加载器,应用程序类加载器

双亲委派模型

除了顶层加载器,每个类加载器都需要有父类加载器,在查找类或者资源时会将搜索任务委派给父类加载器,父类加载器无法加载才会返回给子类加载器,避免重复加载

打破双亲委派机制需要重写loadClass方法

数据结构

优先队列

通过堆实现

子树中每个元素都大于或小于根元素

插入和删除元素效率高,是O(log(n)),初始化效率是O(n)

插入元素

首先插入在最尾,大于父节点则和父节点交换

删除堆顶元素

自底向上堆化:比较根节点左右,选大的放堆顶,然后向下递归

自顶向下堆化:把最后一个元素放入堆顶,不断和左右子节点比较并交换

堆排序

1.建堆,对所有非叶子结点自顶向下堆化

2.排序,取出堆顶元素放入数组末尾,然后自顶向下堆化

二叉树第i层最多有2^(i-1)个节点,深度为k的二叉树最多有2^(k+1)-1个节点,最少有2^k个节点

父节点序号为i,则左右孩子序号分别为2i和2i+1

平衡二叉树

左右子树深度差不超过1

二叉树存储

链式储存(存储左右节点地址),顺序储存(按照完全二叉树标序号方式)

排序算法

计算机网络

七层体系结构

应用层,表示层,会话层,传输层,网络层,数据链路层,物理层

四层模型

应用层,传输层,网络层,网络接口层

HTTP从输入URL到页面展示发生了什么

1.输入URL

2.通过DNS协议获取IP地址

3.根据IP地址和端口号发送TCP连接

4.发送HTTP请求报文

5.处理请求并返回响应报文

6.解析HTML代码,并根据需求资源再次发起HTTP请求

7.不需要通信时可以主动关闭TCP连接

HTTP常见状态码

1xx信息性状态码,2xx成功状态码,3xx重定向状态码,4xx客户端错误状态码,5xx服务端错误状态码

HTTP和HTTPS的区别

1.HTTP端口号80,HTTPS端口号443

2.URL前缀不同

3.HTTP运行在TCP上明文发送;HTTPS在SSL/TSL上运行,采用对称加密

4.搜索引擎更推荐HTTPS偏好

HTTP1.0和1.1区别

1.1.0短连接,1.1长连接

2.1.1新增多个状态响应码

3.缓存机制不同

4.1.1新增range区域,允许请求对象的一部分,节约带宽

5.1.1引入了host头字段,可以在一个主机上托管多个ip地址

HTTP1.1和2.0区别

多路复用(同一链接处理多个请求),二进制帧,头部压缩,服务器推送(推送相关资源)

HTTP2.0和3.0区别

QUIC传输协议,支持1个或0个握手建立连接,一个连接建立多个数据流避免队头阻塞,更快错误恢复,安全性更强

HTTP2.0中TCP阻塞了怎么办

1.并发TCP连接(增加单个域名下的TCP连接数)。2.域名分片(增加域名)

TCP头阻塞是发送失败会等待重发

HTTP阻塞是分为管道和非管道化,一个TCP上可发多个http请求,非管道化完全串行;管道化并行发送,串行响应,需要幂等请求

 http2使用一个域名单一TCP连接发送请求,请求包被二进制分帧,不同请求可以互相穿插,避免了http层面的请求队头阻塞。但是不能避免TCP层面的队头阻塞。

HTTP使用Session保存用户状态

URI和URL区别

URI标识资源,URL还标识了如何定位资源

Get和Post区别

获取和提交资源,get幂等,get参数在路径中,Post参数在请求体内,get可以缓存,

WebSocket

基于TCP的全双工协议

PING

监测网络连通性

基于互联网控制报文协议ICMP实现,通过收发报文实现

DNS

域名管理系统,解决域名和IP地址的映射问题,DNS应用层协议,端口号53,基于UDP

根DNS服务器,顶级域名服务器,权威DNS服务器,本地DNS服务器

迭代查找,递归查找

TCP和UDP区别

TCP面向连接,可靠传输,有状态,传输效率低,面向字节流(UDP面向报文),首部开销大,只支持点对点通信

UDP即时通信,TCP文件传输

HTTP3.0以前基于TCP,3.0基于UDP,使用QUIC协议

为什么要三次握手

可能会有遥远的第一次握手信号传来,导致错误开启链接

第三次握手可以携带数据

为什么要四次挥手

客户端发送最后一次确认信息后等待2倍MSL最长报文段寿命,防止服务器未收到确认信息一直重发

服务端收到客户端消息则刷新保活器时间2小时,每隔75秒发送一次,十次未收到则关闭连接

TCP粘包和拆包

tcp只有流没有包。MSS最大长度为1500-40,数据包大小超过则拆包,不足则粘包

udp有数据保护边界,数据包一个一个发送

粘包问题是因为多个包粘连在一起无法分离

发送方可以关闭Nagle算法,接收方通过应用层获取到数据包长度,可以设置开始和结束符,可以连数据包长度一起发送

实现可靠UDP

应用层超时重传,确认序列号

TCP缓冲区

输入和输出缓冲区,每个字节有序列号,数据进入缓存区则函数返回,由TCP协议负责

TCP流量控制(滑动窗口,反馈调节,零窗口探测)

TCP拥塞控制(慢开始,拥塞避免,快重传,快恢复)

TCP保证可靠性

基于数据块传输,对失序数据包重新排序并去重,校验和,重传机制,流量控制,拥塞控制

IP

每个设备分配一个IP地址,发送请求时包括源和目的地IP地址,用于定位

MAC地址

网络设备的身份证号,用于寻找特定设备,可以移动

ARP

广播问询,单播响应

操作系统

用户态和内核态

用户态可以直接读取应用程序数据,权限低

内核态可以访问计算机所有资源,权限高

用户态到内核态可以通过系统调用(需要操作系统介入协助操作,通过trap切换状态),中断,异常

用户线程和内核线程区别

用户线程切换和创建成本低,在用户空间内实现,但不能使用多核,

内核线程相反

用户线程和内核线程可以一对一,多对一,多对多

线程同步方法

互斥锁,读写锁,信号量,屏障,事件(通知)

PCB进程控制块

每个进程有自己的PCB,操作系统会根据PCB中信息调度进程

进程间通信方式

进程调度算法

FIFO,轮询,多级反馈队列,优先级队列,剩余时间最少优先

僵尸进程

子进程终止,父进程还在运行,父进程未调用wait或waitpid获取子进程状态信息,释放子进程内存

孤儿进程

子进程运行,父进程意外终止或未调用wait或waitpid,孤儿进程的父进程设置为init(进程号为1),回收孤儿进程

内存管理

内部碎片,外部碎片

连续式内存分配,非连续式内存分配

虚拟内存

隔离进程,提升物理内存利用率,简化内存管理,多个进程共享物理内存,提升内存安全性,提供更大内存空间

分段内存分配

通过段表记录虚拟地址值和物理地址映射,虚拟地址包括段号和偏移量

通过段号不一定能找到对应的物理内存,可能被删除或未创建

容易在段之间留下内存碎片

分页内存分配

通过页表记录虚拟地址值和物理地址映射,虚拟地址包括页号和偏移量

分页和分段区别

都是非连续内存分配,都是地址映射

页大小固定,段大小不固定;页是物理单位,段是逻辑单位;分段出现外部内存碎片,分页出现内部内存碎片;分别使用页表和段表映射;分页无要求,分段需要手动分段,显式设置段寄存器

TLB快表

缓存页表的映射

换页机制

内存不够时,将页放到磁盘上

页缺失

硬性缺失,没有对应物理页,交由MMU建立物理页

软性缺失,未建立映射,交由MMU建立映射

页面置换算法

最佳页面置换算法,FIFO(Belady现象,频繁使用的页面会被经常换出),最近最久未使用页面置换算法,最少使用页面置换算法,时钟页面置换算法

局部性原理

时间局部性,最好在较短时间密集访问核数据

空间局部性,和访问指令相关的指令集中放在一个较小区域内

硬链接和软链接

硬链接:通过inode建立连接,互为硬链接,删除其中一个没有影响,只有删除了源文件和所有对应的硬链接文件才会被彻底删除。

不能对目录或不存在的文件创建硬链接,不能跨越文件系统(硬链接和文件的inode一致,每个文件系统有自己的inode表)

软链接:指向一个文件路径,源文件删除软链接依然存在,只想无效的文件路径,类似于快捷方式

可以。。。可以。。。

提高文件系统性能

磁盘调度算法

设计模式

装饰器模式

在不改变原有对象的基础上扩展其功能

对实现最底层功能的类进行包装,提供更丰富的API灵活便捷处理

适配器模式

用于接口不兼容的类协调

被适配的为适配者,适配的是适配器,对象适配器组合实现,类适配器使用继承实现

工厂模式

使用静态工厂或普通工厂创建对象

观察者模式

监听服务

SpringMVC

什么是MVC

Model,View,Controller

什么是DAO层

Data Access Object,访问数据库

MVC流程

Dispatcher >> HandlerMapping >> HandlerAdapter >> Handler >> ViewResolver

Dispatcher为主控

@RequestMapping

处理路径映射

@RequestParam

请求参数绑定

@PathVariable

路径参数接收

@RequestBody

JSON参数接收

如何进行请求拦截

过滤器对整个Web拦截,拦截器对MVC中Controller请求拦截,SpringAOP对Controller外的Bean请求进行拦截

Mybatis

#和$的区别

#是先创建预编译的SQL语句,执行到时再替换掉占位符 ? 

$是进行字符串拼接,会被SQL注入,但是可以处理一些无法预编译的情况

如何绑定XML和Mapper接口

在xml文件中,将mapper标签的namespace与接口全限定符绑定

默认分页和手写分页哪个效率高

默认分页的偏移量大时效率低

Mybatis缓存机制

一级缓存本地缓存sqlSession,方法参数结果保存在map中,如果一样直接返回结果,默认开启不能关闭

二级缓存sqlSessionFactory,cacheEnable默认启用,要配置在Mapper.xml中,select语句缓存,增删改语句刷新缓存,使用LSU最近最少使用算法收回,根据时间表刷新,存储集合或对象的1024个引用,缓存对象可读可写,非共享,不会干扰潜在的修改

Servlet

cookie和Session区别

存储位置不同,存储容量不同,存储方式不同,隐私策略不同,生命周期不同,服务器压力不同,浏览器支持不同,跨域支持不同

Cookie不安全,Session服务器压力大

get和post区别

浏览器回退post会重发请求;get的url地址可以被bookmark;get会被浏览器主动cache,post需要手动设置;get只能url编码;get参数会被完整保留在浏览器历史记录中;get请求在url中参数长度有限制;get只接受ACSII字符;get参数暴露在url上,post参数在Requestbody中

post不幂等

幂等指多次发送同样的请求作用一样,post会导致多次创建资源

错误码

  • 15
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值