面试总结
1. 设计一个秒杀系统?
答:1使用Redis
2公平性:使用一个线程池对来的线程按程序服务
3防止机器人交易:使用验证码
4保证线程安全就是商品不会卖出负数
5缓解服务器压力 使用分布式
6使用异步队列,把可以滞后的数据比如积分之类的可以使用优先队列处理。
待补充。。。。。。
2.java的基本数据类型?
答:1数值型:int long short double float byte
2布尔刑boolean
3.StringBuilder和StringBuffer,String
答:1.执行速度方面StringBuilder>StringBuffer>String
因为:String是字符串常量也就是不可改变的,平时我们对字符串常量的改变是jvm对我们的欺骗,str=str+"1";jvm是会去字符串常量池里面把原来的对象gc,然后重新创建一个对象。
StringBuilder比StringBuffer快的原因是后面一个是要加锁的。
4.谈一谈final
答:1.final关键字修饰变量,代表这个变量不可修改。如果和static一起用则表示全局常量
2.final方法是表示子类不可以覆盖这个方法
3.final类是不可以继承的类
可以联想到模版设计模式
5.事务中savepoint的使用
设置保存点 savepoint a
取消保存点回退到保存点 rollback to a
取消全部事务 rollback
6.谈一ACID
A:atom:原子性是表示一段SQL语句要么全部执行要么不执行
C:Consistency:事务开始和事务结束后不会对关系数据发生破坏
I:Isolate隔离性:多个事务是隔离的,就是事务之间互不影响
持久性(Durability):就是锁数据应该是持久保存的,不应该应为服务器崩掉而消失
7.谈一谈HashMap
答:1 hashMap是使用数组加链表实现的数据结构,他里面有一个
Entry是对应数组加链表里面的链表
2 它里面的默认加载印子是0.75,加载因子表示hash表中元素的填满程度,加载因子越大,冲突就越大。
3 它在存储时是先获得hash值,然后获取hash值在table里面的位置。
4 里面和ArrayList和LinkedList一样都有一个modCount来判断会不会抛出ModfiCurrentException
5 然后如果有值在则会扩容到下一个
6 也实现了Iterator接口
8.谈一谈volatile
1 从计算机的角度来看:如果有volatile声明的变量会在转换成汇编代码时在前面加一个lock关键字。有lock关键字会将当前缓存回写到系统内存,然后会使得其他CPU缓存该地址的数据无效
2 从jvm的角度来看,java虚拟机有自己的内存模型(Java Memory Model,JMM)。jmm给每个线程都分配了本地内存,本地内存保存了被该线程使用到的主内存的副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量。当写一个volatile变量时,JMM会把该线程对应的本地内存中的变量强制刷新到主内存中去;这个写会操作会导致其他线程中的缓存无效。
3 volatile还有一个特性:禁止指令重排序优化
例如:a=1;b=2;c=a+b这三个操作,第一步(a=1)和第二步(b=2)由于不存在数据依赖关系,所以可能会发生重排序,但是c=a+b这个操作是不会被重排序的,因为需要保证最终的结果一定是c=a+b=3。
若用volatile修饰共享变量,在编译时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序
9.谈一谈jvm的内存模型
1 jvm的内存模型分为虚拟机栈,本地方法栈,堆区,程序计数器,方法区。
程序计数器:没开启一个线程都会开辟一个程序计算器,它里面是一个指针指示执行到哪行代码
2 jvm栈:里面存储了一些局部变量表,操作数栈,方法信息等。每次执行一个方法都会开辟一个栈帧。比如常用的对象的引用就是存储在里面。
3 本地方法栈和jvm栈是类似,但是它是调用本地方法所使用的空间。
4 java堆区这是GC主要收集的地方。这里面存放的是对象的实例。在编程的时候会遇见堆溢出,我们要做的是调整-Xmx -Xms为一样大。初始化堆区的大小,这是被所有线程共享的
5 方法区:存储的是类信息,常量,静态变量。java编译成class后会加载到方法区。
6 运行是常量池,java文件编译成class文件第一项是魔数标志是什么版本的java的文件,第二项是常量池,运行时常量池就是把这个常量池加载进来。
10.谈一谈jvm的GC
如果对象GCRoot无法到达则会被视为垃圾对象,可以作为GCRoot的对象是方法区中类静态属性引用对象。其中对象有必要回收,就会把它放在F-Queue队列中,然后jvm会开一个线程去回收。
垃圾回收有三种算法分别是:标记-清除,整理,标记整理算法。
标记-清除:将垃圾区域标记,到标记到一定的时候将标记的区域一一清除,这就是有些效率不足。
复制算法:将内存一分为二,然后将有用的数据复制到空内存中,然后集中一次性清理垃圾内存。
标记-整理算法:将垃圾内存一一标记,然后将存活对象移动到一端。在将另一端的垃圾清理掉。
对象一般是先分配到eden区当内存满了以后,会进行一次mirror GC对象就到了survivor区,每次mirror GC一次在survivor空间还活在,对象的年龄就会增加一次,当到了一定年龄就会到老年代去。
其中survivor有两个差不多大小的survivor,并且有一个survivor是不用的,所有在这里可以使用复制清理算发。
10.谈一谈spring中的IOC
ioc:控制反转是spring的核心。所谓IOC,对于spring而言,就是由spring来负责控制对象的生命周期和对象之间的关系。spring倡导的方式所有的类都是在spring的容器中以bean形式登记,你可以告诉spring你是什么东西,你需要什么东西,然后在适合的时候spring会给你。同时类的创建和销毁这都是spring在控制,所以叫做控制反转。DI依赖注入,动态的向某个类提供对象,这些都是通过反射技术做到的。
为什么不用工厂模式而使用IOC。其实本质上还是因为IOC是通过反射机制来实现的。当我们的需求出现变动时,工厂模式会需要进行相应的变化。但是IOC的反射机制允许我们不重新编译代码,因为它的对象都是动态生成的。
11.谈一谈spring中的AOP
aop面向切面编程
首先我们谈一谈代理模式 :代理类(proxy class)和真实处理的类(real class)都实现同一个接口,然后代理类需要增强真实类的功能,一般是在代理类里面持有真实类的引用,然后调用real 的方法。
在说一句,代理模式和装饰模式的区别是:使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例。并且,当我们使用装饰器模 式的时候,我们通常的做法是将原始对象作为一个参数传给装饰者的构造器。
在spring中比如事务管理、日志、缓存等等都是重复的切面操作,所以要使用aop。AOP代理主要分为静态代理和动态代理,静态代理的代表为AspectJ;而动态代理则以Spring AOP为代表。
AspectJ的静态代理,它会在编译阶段将Aspect织入Java字节码中, 运行的时候就是经过增强之后的AOP对象。
Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
12.谈一谈Executor框架
java程序把应用分解成多个任务,EXecutor把任务映射成固定线程数。在底层,os把这些线程映射到硬件处理器上。
主要包括三个部分:任务是包括Runnable接口和Callable接口。
执行任务是继承Executor的ExecutorService接口。异步计算结果Future接口和FutureTask类。
通过Executors工具类可以创建不同的线程池ThreadPoolExecutor:SingleThreadExecutor、FixedThreadPool和CachedThreadPool。
如果需要计算后的结果,通过futureTask来获得Call方法的返回结果。
里面有一个LinkedBlockingQueue作为缓冲线程池的线程。
13.谈一谈AQS框架
在concurrent包下面提供了ReentrantLock/Semaphore/CountDownLatch,这些都是lock接口下面类,可以实现同步。
它们里面都有一个aqs的抽象类。
它维护了一个volatile int state(代表共享资源)和一个FIFO线程等待队列(多线程争用资源被阻塞时会进入此队列)。
不同的独占锁和共享锁实现不同的方法就可以实现独占方式和共享方式。
里面的线程都是尝试去获得独占资源,其他线程可以以快速形式插入等待队列或者以自旋方式进入FIFO线程队列。
共享模式下线程获取共享资源的顶层入口。它会获取指定量的资源,获取成功则直接返回,获取失败则进入等待队列,直到获取到资源为止,整个过程忽略中断
共享模式下线程释放共享资源的顶层入口。它会释放指定量的资源,如果彻底释放了(即state=0),它会唤醒等待队列里的其他线程来获取资源
14.谈一谈三次握手
第一步:客户端发送一个TCP的SYN=1表名客户端打算和服务端要连接,以及初始序列号是X,保存在报头的序列号
第二步:服务端发送确认ACK,即SYN和ACK标志均为1,将确认序号设置为客户端的seq+1,即X+1;
第三步:客户端再次发送确认(ACK)SYN标志为0,ACK标志为1.并且把服务器发来ack的序号字段+1,放在确定字段中发送给对方.并且将seq+1发送
15.谈一谈四次挥手
加入client发送中断请求,首先client会发送一个FIn报文给server端。意思是说"我Client端没有数据要发给你了",但是如果你还有数据没有发送完成,则不必急着关闭Socket,可以继续发送数据。所以你先发送ACK,"告诉Client端,你的请求我收到了,但是我还没准备好,请继续你等我的消息"。这个时候client进入了FIN_WAIT状态,继续等待Server端的FIN报文。当Server端确定数据已发送完成,则向Client端发送FIN报文,"告诉Client端,好了,我这边数据发完了,准备好关闭连接了"。Client端收到FIN报文后,"就知道可以关闭连接了,但是他还是不相信网络,怕Server端不知道要关闭,所以发送ACK后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。“,Server端收到ACK后,"就知道可以断开连接了"。Client端等待了2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,我Client端也可以关闭连接了。Ok,TCP连接就这样关闭了!
16.在浏览器中输入www.baidu.com后执行的全部过程
1.客户端通过DNS解析成ip地址,通过ip地址找到服务区路径。客户端发起http会话到服务器,然后通过tcp封装到网络层
2、在客户端的传输层,把HTTP会话请求分成报文段,添加源和目的端口,如服务器使用80端口监听客户端的请求,客户端由系统随机选择一个端口如5000,与服务器进行交换,服务器把相应的请求返回给客户端的5000端口。然后使用IP层的IP地址查找目的端。
3.客户端的网络层不用关心应用层或者传输层的东西,主要做的是通过查找路由表确定如何到达服务器,期间可能经过多个路由器,这些都是由路由器来完成的工作,我不作过多的描述,无非就是通过查找路由表决定通过那个路径到达服务器。
4.客户端的链路层,包通过链路层发送到路由器,通过邻居协议查找给定IP地址的MAC地址,然后发送ARP请求查找目的地址,如果得到回应后就可以使用ARP的请求应答交换的IP数据包现在就可以传输了,然后发送IP数据包到达服务器的地址。