1. i++是原子的吗?为什么不是原子的?会出现什么情况?
答:i++不是原子,因为底层的过程是分为先取值,再加1,最后赋值。而不是一步完成,当一个线程取完值的时候,可能失去了CPU的执行权,而其他线程也是取到原来的结果。
2.数组的特点?底层如何定位到数组中的元素?数组的内存空间是连续的吗?
答:数组的查找速度较快,因为是通过下标直接查找的,但创建对象时需要连续的存储空间,并且长度不可变。
因为数组是连续的存储空间,只需要获得偏移量就可以定位到数组中的元素。
1、 tcp三次握手
主动打开连接的客户端和被动打开的服务端都结束closed阶段,服务端进入listen阶段
(1) 第一次握手:建立连接,客户端发送syn包和序列号x到服务器,并进入syn-sent阶段。
(2) 第二次握手:服务器收到syn包,返回标志位SYN、ACK和序列号y还有 ack=x+1,进入SYN-RECD
(3) 第三次握手:客户端收到服务器的确认TCP报文之后,返回最后一段TCP报文,包括标志位ACK,Seq =
x +1(表示收到服务器端的确认后ack), ack =
y+1(表示收到服务器端的序号seq),进入established阶段
当服务器端收到客户端的确认报文后,也进入established阶段,完成三次握手。
在这传输过程中,确定了双方的确认号ack和序列号seq的值,保证了tcp报文传输的连贯性。
2、 tcp四次挥手
(1) 第一次挥手:客户端主动关闭,发送释放连接报文,并停止发送数据。报文包括FIN =1,seq = u(已传送过来数据最后一个字节的序号再+1),并进入FIN -WAIT-1状态。
(2) 第二次挥手:服务端收到连接释放报文,发出确认报文,ACK=1,ack=u+1,带上自己的序列号v,然后进入Close-wait状态。客户端接收到确认报文后FIN-WAIT2状态。处于半关闭状态,客户端到服务端方向的连接释放了,但服务端还能继续向客户端发送数据。
(3) 第三次挥手:服务器将最后的数据发送完成之后,就想客户端发送释放报文,FIN=1,ack=u+1,序列号为w(发送的数据最后一位序号+1),并进入last-ack状态。
(4) 第四次挥手:客户端收到服务器的释放报文,发出确认报文,ACK=1,ack=w+1和自己的seq = u+1,并进入TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2MSL时间后,才进入Closed状态。
服务器端收到客户端的确认报文后,立即进入closed状态。
3、优化TIME_WAIT状态过多
(1) 扩大端口范围
(2) 开启重用,允许将time-wait sockets重新用于新的TCP连接。
4、说说select、epoll(不懂)
5、进程间通信
(1) 管道:一种半双工的通信方式,数据只能单向流动,而且只有具有亲缘关系的进程间使用。亲缘关系通常指父子进程。
有名管道:也是半双工的通信方式,但它允许无亲缘关系进程间的通信。
特点:面向字节流;
生命周期随内核
自带同步互斥机制
半双工,单向通信,两个管道实现双向通信
(2) 信号量:是一个计数器,用来控制多个进程对共享资源的访问。请求资源时,信号量大于0,表示可获得,若为零,则将进程挂起。若有资源被释放,查看是否有进程被挂起,有就唤醒,如果没有,就将信号量+1。
对临界资源进行保护
(3) 消息队列:在内核创建一个队列,队列中每个元素是一个数据包,不同的进程可以通过句柄去访问这个队列。克服了信号传递信息少,管道只能承载无格式字节流。
特点:消息队列可以认为是一个全局的链表,链表节点中存放这数据包的类型和内容,有消息队列的标识符进行标记。
消息队列允许一个或多个进程写入或者读取消息
消息队列的生命周期随内核
消息队列可实现全双工通信。
(4) 信号:在软件层次上对中断机制的一种模拟,它是比较复杂的通信方式,用于通知进程有某件事件发生,一个进程收到一个信号与处理器收到一个中断请求效果上可以说是一致的。
(5) 共享内存:映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC(进程间通信)方式。它往往与其他通信机制配合使用,如信号量。
(6) 套接字:套接字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同设备的进程通信。
6、liunx的常用命令
Ls :当前目录、文件
-l显示详细信息(list)
-a显示隐藏文件(all)
Mkdir 创建目录
-p创建目录,若无父目录,则创建p(parent)
Cd 切换目录
Touch 创建空文件
Echo 创建带有内容的文件
Cat 查看文件内容
Cp 拷贝
Mv 移动或重命名
Rm 删除文件
-r递归删除,删除子目录及文件
-f强制删除
Find搜索文件
Wc统计文本中行数、字数、字符数
Grep在文本文件中查找某个字符串
Rmdir删除空目录
Tree树状结构显示目录
Pwd显示当前目录
ln 创建链接文件
more、less 分页显示文本文件内容
head、tail 显示文件头、尾内容
ctrl+alt+F1 命令行全屏模式
7、jvm的内存模型
分为虚拟机栈,本地方法栈,程序计数器,方法区,堆。
虚拟机栈:为java方法服务,存放8种基本类型的变量+对象的引用变量+实例方法
本地方法栈:为native方法服务,与虚拟机栈作用类似,调用本地方法,在本地方法栈创建一个栈帧,用于存放本地方法的局部变量表、操作数栈、动态链接、出口信息。
程序计数器:字节码解释器通过改变程序计数器的值来依次读取指令,实现代码的流程控制,如顺序,循环,选择,异常处理。
在多线程的情况下,记录记录当前执行的位置,当线程被切换回来的时候能够知道该线程上次运行到哪里。
方法区:存放编译后的类信息,静态变量,常量等信息。
堆:存放几乎所有的对象实例,99%的GC都发生在这里。
前三个是线程私有的,生命周期比较短,不用GC。
8、垃圾回收
几乎所有GC都发生在堆中,因为堆的生命周期比较长,容易产生垃圾。
堆可以逻辑上分为新生区(eden区,幸存一区,幸存二区)、养老区,元空间
GC分为两类,普通GC和fullGC,都是当区内内存达到阈值时触发。
普通GC发生在新生区,eden区幸存下来的对象移动到幸存区。
fullGC发生在养老区。
GC的四大算法:
(1)、引用计数法:用一个表记录每个对象被引用的次数,但当两个对象引用时,无法清除,已经被淘汰。
(2)、复制算法:用于年轻代,将幸存0区的对象复制到幸存1区,效率快,而且没有内存碎片,但需要两倍的内存空间。
(3)、标记清除:用于老年代,扫描两次,第一次先标记存活的对象,第二次进行清除,不需要额外的空间,但需要扫描两遍,效率低,存在内存碎片,而且进行fullGc时需要停止服务,否则会误清。
(4)、标记压缩:用于老年代,先扫描标记存活的对象,然后进行压缩,移动存活对象,效率不高。
(5)、标记清除压缩:用于老年代,多次标记清除后,再执行压缩,可以减少移动对象的成本。
9、Threadlocal(待补充)
10、快排:找一个基准(一般为数组的第一位),设置一个起点,一个终点,以基准为中心,分为前后两部分(小于基准 --- 基准---大于基准),比如start= 0,end =n-1,判断end位置的值是否小于基准,小于与start位置交换,大于end往前移,直到交换;然后就换移动start直到交换,当start位置的值大于基准交换,重复以上步骤到end<=strat,就分成了两部分,对这两部分再进行排序,递归。
平均时间复杂度为O(N * logN),最坏的情况复杂度为O(N*N)
11、mysql索引
索引就像书的目录,可以大大提高你在数据库中的搜索查询速度。
优点:加快速度搜索速度;
加快表与表之间的连接速度;
提高分组和排序的速度
缺点:需要花费时间去建立和维护索引,并切随着数据量的增加,所需要的时间也会增加。
索引会占用存储空间
进行增删改数据时,需要动态维护索引,保持其结构不变,需要一定的时间性能开销。
12、mysql分页查询优化
使用子查询优化:
select * fromorders_history where type=8 limit 100000,1; ----------3674ms
select id fromorders_history where type=8 limit 100000,1; ----------1315ms
select * fromorders_history where type=8 and id>=(select
id from orders_history where type=8 limit 100000,1)
limit 100; ----------1327ms
select * fromorders_history where type=8 limit 100000,100; ----------3710ms
分库分表查询,先select id,再select *.