1.垃圾回收算法
1.标记-回收算法
- 两个步骤:
①标记需要回收的对象
②同一回收被回收的对象 - 两个问题:
①效率低下
②产生内存碎片 - 解决方案:
①使用GC
2.复制算法
- 内存需求:
①需要两块大小相等的内存,但每次只使用其中的一块内存。
②在新生代中会将内存划分为一个Eden和两个Survivor。内存大小为8:1。 - 初始状态:
①:只使用了Eden区和一个Survivor区来存放对象。 - GC操作:
①会将存活下来的Eden区和Survivor区中的对象转移到另一个Survivor区,如果这时候超越了Survivor区的内存大小,会用Eden区的内存作为担保。
②将该Survivor区的年龄加1,变成Eden区。 - 作用:
①有效的解决了效率和内存空间碎片的问题。
3.标记-整理算法
- 标记过程:
①与第一个算法过程一致。 - 整理过程:
①使对象想同一边移动 - 作用:
①良好的解决内存碎片问题
4.分代收集算法:结合了以上算法
2.AutomicInteger实现原理
待填充
3.synchronized和lock的区别
- 相同点:
①使用使用lock可以完成synchronized所有的功能 - 用法区别:
①synchronized可以作用于代码块/方法/类上。()内表示需要被锁住的对象,作用在方法上表示锁住this对象,类上表示锁住该类。
②synchronized可以自动释放锁。由编译器保证加锁解锁从而避免手工释放锁造成死锁.而lock需要自己使用lock.lock()开启锁,使用lock.unlock()释放锁,并且只能在finally()从句中释放锁。lock还允许以tryLock()非阻塞的方式获取锁。 - 性能区别:
①ReentrantedLock的功能多于synchronized,多了锁投票,定时锁的功能。在小规模的竞争上synchronized的性能高于lock,在大规模的竞争synchronized的性能下降,而lock的性能基本不变。
但在synchronized锁优化之后,也增加了偏向锁,轻量级锁,自旋锁.导致两者性能相近.但官方推荐使用synchronized.
②ReentrantedLock还具备三个独有特性:- 1.指定非公平锁或公平锁.
- 2.提供Condition(条件)类,分组唤醒线程.而不像synchronized只能唤醒一个或全部.有较高灵活性.
- 3.通过lock.lockInterruptibly()提供锁中断机制.
- 锁机制:
①lock锁的机制:lock可以通过tryLock()非阻塞方式获取锁,需要自己定位释放锁,否则会引起死锁。除此外lock还需要一个锁变量和队列来维护同步。
②synchronized的机制:获取和释放锁都是在块中进行,不会引起死锁。
4.gc停顿原因,如何降低GC停顿
- what?
①整个分析阶段冻结在某个时间点上。可表现为在web界面出现500状态码等服务器错误。如果GC停顿发生在支付阶段,将导致支付失败,对企业造成直接经济损失。因此要尽量避免此类事件的发生。 - why?
①避免在分析阶段对象间的引用关系仍然不断发生变化而可能导致的分析不准确。 - how?
在Serial的老年代垃圾收集器中,会把所有线程的暂停,停下来收集哪些是死亡对象。在CMS和G1中都采取了初始标记、并发标记、短暂GC停顿重新标记,初始标记会直接记录能GC ROOTS 关联的对象,在并发标记的时候有一个线程来标记,这个时候对象的发生的变化都会记录下来,在重新标记的时候会修正,这样就会降低GC停顿时间
5.jvm如何调优,参数怎么调?如何利用工具分析jvm状态?
- 合理划分内存分配:
①合理划分堆栈大小
②合理分配新生代老年代内存比例
③适调新生代中Eden区和Survivor区内存比例 - 采用合适的垃圾处理器,降低GC停顿:
①新生代采用serial垃圾回收器
②老年代采用cms并发标记
③尝试采用GI垃圾回收器
6.jvm中类加载过程
-
加载
①在类加载器的协助之下将对应的.class字节码文件载入内存中。
②将.class文件中的静态数据转换为方法区中的运行时数据结构。
③在堆中生成代表这个类的java.lang.Class对象,并作为方法区类数据的入口
- 链接:指将java的二进制代码合并到jvm中进行运行的过程
- 1 验证:加载的类信息符合jvm的安全规范。
- 2 准备:正式为static变量在方法区分配内存并进行初始化的过程。
- 3 解析:将字符串常量池中的符号引用转换为直接引用的过程。
- 初始化:执行类构造器,合并static语句,初始化顺序由static的顺序决定。
- 当类被引用的加载,类只会加载一次
- 类的主动引用(一定会发生类的初始化)
- new一个对象会初始化该类
- 调用类的static属性(非final)或方法时
- 使用java.lang.reflect包下的类进行发射时
- 发起java Demo1 虚拟机启动时会初始化该Demo1类,即初始化main方法所在的类
- 当初始化一个类而其父类没有初始化的时候
- 类的被动引用(不一定会发生类的初始化)
- 调用一个类的static域的时候,只有真正申明该域的类才会初始化
- 通过子类调用父类的静态变量不会引起子类的初始化
- 通过数组定义类的引用,不会导致该类的初始化
- 引用常量不会导致该类的初始化(原因在于常量在编译阶段就加载进入了常量区)
- 类的主动引用(一定会发生类的初始化)
7.说说java锁的原理
-
1 对于synchronized:
- 通过反编译可以获知在同步代码块前后加入了monitorenter和monitorexit两个字节码。
- 这两个字节码都需要两个一个引用类型的参数来指定需要锁定的和解锁的对象。
- 如果指定了就使用被指定的对象,如果没有的话就需要根据是static方法还是普通成员方法来确定。
- 在执行monitorenter指令的时候会判断是否进入了?如果进入了会将锁计数器加1;否则会继续等待并和其他线程竞争。出锁的时候会将锁的计数器减1,也就是释放锁。
- 要注意的一点是java的线程是映射到系统的原生线程之上的。要阻塞或者唤醒一个线程都需要操作系统的帮助。而从用户态到核心态的转换,需要耗费处理器更多的时间,有时甚至比用户的代码执行时间还要长。
- jdk1.6对synchronized进行了优化,比如说:锁粗化,锁自旋,锁消除,轻量级锁,和偏向锁。
-
2 对于ReentrantedLock:
- when:当一个线程请求其他线程持有的对象锁时,该线程会阻塞;而当一个线程请求获取自身持有的对象锁时,如果该锁时可重入锁,请求成功,否则阻塞。
- so:java中获取锁的粒度是“线程”,而非“调用”。并非每一次调用都会建立一把锁。
- how:可重入锁的一种实现方式是为每一把锁关联一个锁的持有线程和计数器。当计数器的值为0时,表示该锁没有被任何线程持有,每个线程都有机会获取该锁并调用相应的方法。而一旦某个线程获取该锁,jvm会记下该锁的持有线程,并将对应计数器的值置为1;其他线程想要获取该锁,就必须等待。而如果是又同一个线程想要获取这个锁,就可以再次拿到这把锁,并将计数器递增。当着该线程退出同步代码块,会将计数器递减直至为0,此时将释放该锁。
-example:正因如此,在下面的java demo中,由于其内置锁是可重入的,才不会导致死锁:
public class Child extends Father{
public static void main(String[] args) {
new Child().doSomething();
}
public synchronized void doSomething(){
System.out.println("child");
super.doSomething();
}
}
class Father{
public synchronized void doSomething(){
System.out.println("Father");
}
}
- 综上所述:可以得到的结论是:
- 可重入的意思通俗来说就是拿到一把锁,在调用该锁所包含的代码就不需要等待就可以获取锁。
- 子类调用复写的父类的方法时,除了获取子类本身的锁外,还获取了父类的锁。
8.线程和进程的区别
- what?
- 1.进程是一段正在执行的程序,是资源分配的最小单位。而线程又称为轻量级“进程”,它是程序执行的最小单位。
- 2.一个进程可以有多个线程,而每个线程共享程序的内存空间(比如说堆空间)和一些进程级别的资源。
- 3.线程有四态:就绪,运行,挂起,死亡。
- difference?
- 一个进程拥有独立的堆栈空间和数据段,每运行一个进程需要分配给他独立的内存空间。需要建立众多的数据表来维护代码段数据段和堆栈段。这会导致系统的开销较大。而线程拥有独立的堆栈空间,彼此之间使用相同的地址空间、共享大部分数据
,比进程更节俭、开销小、切换效率高。但也因为进程拥有独立的内存空间,使得进程的安全性更高,当一个线程崩溃之后,在保护状态下的进程不会对其他进程产生影响。而一个线程则相当于一个进程的不同执行路径。一个线程的死亡宣告着整个进程的死亡。 - 由于进程独立的内存空间,导致进程之间的通信需要借助于管道,信号,共享内存,套接字等方式。而线程则可以非常方便的使用共享数据段进行通信。
- 进程的进程控制块称为PCB,线程的线程控制块称为TCB。
- 一个线程只能属于一个进程,而一个进程却可以拥有多个线程。
- 一个进程拥有独立的堆栈空间和数据段,每运行一个进程需要分配给他独立的内存空间。需要建立众多的数据表来维护代码段数据段和堆栈段。这会导致系统的开销较大。而线程拥有独立的堆栈空间,彼此之间使用相同的地址空间、共享大部分数据
- when?
- 考虑到资源消耗和代价,频繁的创建和销毁优先选择线程。
- 为提高程序响应,频繁切换、大量计算、耗时的操作优先选择线程。
- 多机分布选进程,多核分布提高cpu利用率优先选择线程。
- 并行操作,c/s架构并行响应用线程。
- 安全至上选进程,效率与速度至上选线程。
9.Spring AOP是怎么实现
- what?
- Aspect Oriented Programming的缩写,面向切面编程。它是通过预编译和动态代理的方式实现程序的统一维护的一种技术。
- major function?
- 日志记录、性能统计、安全控制、事务和异常处理。
- application?
- 提供声明式的企业服务。
- 允许用户控制自己的方面,实现OOP(面向对象编程:一切皆对象)AOP互补使用。
- implemention model?
- 1.预编译:使用AspectJ(spring封装了AspectJ的使用) ,这是一种完整的面向切面编程的解决方案。也是比较常用的一种,好处是可以很容易看清代码结构。
- 2.运行期间动态代理(JDK动态代理,CGLib动态代理):这是两种比较老的方式,配置起来相对繁琐。
- 3.注解方式:开发起来相对简单,但加大了后期的维护成本,比如说:你很难找到使用了SpringAOP的地方。
- key concept?
- Advice:
- 前置通知(before advice):在一个连接点之前进行通知,但是不能组织连接点之前的代码执行(除非抛出一个异常)。
- 返回后通知(after returning advice):在连接点正常执行完后执行通知。
- 抛出异常通知(after throwing advice):在方法抛出异常后退出时执行通知。
- 后置通知(after(finally)advice):不管正常还是异常退出,在方法退出后执行通知。
- 环绕通知(around advice):包围一个连接点(joint point)的通知。
- configuration files:
- spring-aop-schema-advice.xml
- 切面类:
/*
* 声明一个切面类
* */
public class MyAspect {
public void before(){
System.out.println("aspect before");
}
public void afterReturning(){
System.out.println("aspect afterReturning");
}
public void afteThrowing(){
System.out.println("aspect afteThrowing");
}
public void after(){
System.out.println("aspect after(finally)");
}
public void around(ProceedingJoinPoint joinPoint){
Object object = null;
try{
System.out.println("aspect around 1"); //方法执行前
object = joinPoint.proceed(); //代表业务方法的执行
System.out.println("aspect around 2"); //方法执行后
}catch(Throwable e){
e.printStackTrace();
}
}
//AOP中参数的传递
public void aroundInit(ProceedingJoinPoint joinPoint,String bizName,int times){
System.out.println(bizName+"--"+times);
Object object = null;
try{
System.out.println("aspect around 1"); //方法执行前
object = joinPoint.proceed(); //代表业务方法的执行
System.out.println("aspect around 1"); //方法执行后
}catch(Throwable e){
e.printStackTrace();
}
}
}
10.SpringMVC的主要流程
- 1.用户发送请求至前端控制器DispatcherServlet。
-
- DispatcherServlet收到请求调用HandlerMapping处理器映射器。
-
- 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
-
-
- DispatcherServlet调用HandlerAdapter处理器适配器。
- 6.HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
- 7.Controller执行完成返回ModelAndView。
- 8.HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
-
- DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
- 10.ViewReslover解析后返回具体View。
- 11.DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)
- 12.DispatcherServlet响应用户。
11.简单述说Java的内存结构
-
jvm在运行的时候,会将管理的内存划分为几个不同的数据区域:
12.Object有哪些方法(九大方法),clone是深复制还是浅复制,finalize一般在什么时候使用:
- 有哪些方法:wait,notify,notifyall,clone,getclass,toString,equals,hashcode,finalize
- java中什么是浅拷贝,什么是深拷贝:
- java中实现对象的引用复制给另一个对象,一共有三种方式:直接赋值、浅拷贝、深拷贝
- 直接赋值会导致一个对象的变化会立即反映到到另一个对象之上。
- 浅拷贝中原始对象和副本引用相同的对象。值类型的数据则另外复制一份。引用类型的对象的变化还是会导致另一个对象的变化。
- 深拷贝就是在clone()方法里面新建一个自己的对象。但其缺陷却是工作量可能很大。这是可以通过序列化来解决。
- 什么时候调用finallize()
- finallize实在回收某个对象的时候工作,它可以做一些后续的工作,即必要的回收和清理工作,比如说关闭流。但是不推荐调用该方法:原因在于该方法会调用c语言的析构函数,该函数运行代价高,不确性大。而finallize()方法可以做的try{}finally{}都可以做,因此更推荐使用后者。
13.如何管理线程(主要介绍各种线程池的实现)
- 1.首先是使用线程池来管理线程,其次是通过executors工厂来创建线程池的。当线程池达到负载上限的时候,线程会在线程池管理阻塞队列排队等候,而不会无序的竞争cpu。
- 2.java中的多种线程池:
- 1.newFixedThreadPool:固定数量线程的线程池。
- 2.newCachedThreadPool:无限大小的线程池,大小可以自动收缩或扩大。
- 3.newSingleThreadPool:同一时刻只允许有一个线程。
14.如何让线程A等待线程B结束
- 1.使用join方法
- 2.在单线程池中B线程先获得资源运行,则A线程会等待直至B线程运行结束。
15. TCP如何控制拥塞
- what?
- 1.拥塞控制就是防止过多的数据注入网络,避免路由器或者链路过载。
- how?
- 发送方:维持一个叫做拥塞窗口cwnd(congestion window)的状态变量。为了防止cwnd过大引起网络阻塞,还需要设置一个慢开始门限ssthreshold状态变量。ssthreshold的使用方法如下:
- cwnd
- cwnd>ssthreshold的时候,改用拥塞避免算法,也就是加法算法。
- cwnd=ssthreshold时,采用慢开始或者拥塞避免算法随意。
- cwnd
- 发送方:维持一个叫做拥塞窗口cwnd(congestion window)的状态变量。为了防止cwnd过大引起网络阻塞,还需要设置一个慢开始门限ssthreshold状态变量。ssthreshold的使用方法如下:
- 当出现拥塞时:把新的门限值设置为此时窗口一般大小。窗口大小设置为1,然后重新开始上述步骤。
- 当出现连续的三个重传:需要开启快重传和快恢复,发送方重传自己的信息,门限值减半。但这时并不是网络拥塞,不会执行拥塞避免算法。
15.ThreadLocal?
- what:ThreadLocal为该类型的变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。
- how:具体的实现是在每个线程中保存了一个ThreadLocalMap,而这个map的key就是threadlocal,而值就是set的那个值。每次线程get的时候,都从自己的变量中取值,就不存在线程安全问题。
16.OSI模型
17.HTTP
17.1 HTTP1.0 HTTP 1.1主要区别
- 1.长连接:HTTP1.0需要设置connection:keepalive来保持长连接,而1.1默认就支持长连接。支持长连接是因为HTTP是基于TCP/IP协议的,建立一次连接需要经过三次握手,开销较大。而每次通讯都需要重新连接的话,对性能也会有一定的影响。所以最好维持一个长连接,一次连接处理多个请求。
- 2.节约宽带:
- 2.1 HTTP1.1协议支持只传送header信息(不传送body),如果服务器认为客户端有权限访问,就会返回状态码100,否则返回401。当客户端收到100就传送body给服务器,否则不传送。通过这种方式节约宽带。
- 2.2 另外HTTP1.1还支持断点传送,当客户端已经有了一部分资源后。只需要向服务器请求另一部份资源即可。它是文件断点传送的基础。
- HOST域:多个虚拟站点共享一个ip和端口,这在web server比如说tomcat中已经非常常见了。而HTTP1.0不支持该域。
17.2 HTTP 1.1、HTTP2.0主要区别
- 1.多路复用:HTTP2.0采用多路复用技术,可以做到一个连接并发处理多个请求。并且其处理请求的数量是HTTP1.1的好几个数量级。虽然后者可以建立多个连接来并发处理请求,但建立连接是有开销的。另一方面TCP连接还有一个预热和保护的过程,指的是一旦数据传送成功过,才会慢慢地加快传输速度。因此对于瞬时并发连接,HTTP1.1中服务器的响应相对较慢。最好是使用一个连接并且支持瞬时并发传送。
- 2.数据压缩:后者支持采用HPACK算法对header数据压缩,这样数据的体积就会变小,网络传输就会变快。
- 3.服务器推送:当客户端向服务器请求资源的时候,HTTP2.0支持将一些需要的资源一起推送给客户端,免得客户端再次创建连接请求获取。这种方式非常适合加载静态资源。服务端推送的资源就存放在客户端的某处,客户端加载该部分资源就可以走本地而不通过网络,速度自然快了很多。
18.GBK和UTF-8的区别
- 1.GBK包含所有的中文字符。而UTF-8包含的是全世界国家需要的字符。
- 2.GBK的文字编码是双字节的,不管中文还是英文。而UTF-8则是一种多字节编码,它的英文只采用一个字节(8位),而中文则采用三个字节。
- 3.使用:因此对于英文比较多的最好使用UTF-8,对于中文比较多的最好使用GBK。要求通用性比较好就使用UTF-8,但其另外一个缺点是其数据库比较大。
19.一次网站访问的全过程
- 1.主机向DNS服务器发送域名解析请求以获取ip地址。
- 2.应用层采用HTTP协议发送数据。
- 3.数据到达传输层被封装成数据段,主机采用1024以后的随机端口号,而目标端口是80。
- 4.数据到达网络层后被封装成数据包,加入主机源ip地址和目标ip地址。
- 5.数据包到达网络接口层首先会被封装成数据帧,加入源MAC地址和目标MAC地址(这个目标MAC地址是本地网关的MAC地址,在数据转发的过程中,会随着路由器改变)。被封装的数据会转换为物理层的数据流,通过互联网发送到目标服务器。
19. 说出数据连接池的工作机制是什么?
- 1.启动:J2EE服务器启动时,会建立一定数量的池连接。并一直维持不少于这个数目的连接。
- 2.调用:客户端需要连接时,池驱动程序会从返回一个连接并把它标记为忙。如果此时没有空闲的连接,池驱动程序会新阶一定数量的连接,新建连接的数量由配置参数决定。
- 3.释放:当使用的池连接使用结束后,会将该连接标记为空闲,使其可被其余调用。
- 最小连接数与最大连接数:无论是否被使用,连接池都将保持至少有那么多连接数量。而当应用程序请求请求的连接数量超过了最大连接数量时,这些请求会被加入等待队列中。连接数的设置需要考虑以下因素:
-
- 连接使用量,如果过大将导致连接资源浪费。如果太小,将进入等待队列。导致数据库操作。
-
20.存储过程和函数的区别
- 1.存储函数是用户定义的一系列sql语句的集合,涉及特定表或者对象的任务,用户通过参数和存储函数名来调用。而函数则是数据库中已定义的方法。它只接收参数并返回特定类型的值,但并不设计特定用户表。
21。事务是什么
- 1.事务时单个的执行单元,如果事务执行成功,那么事务所更改的数据就会被提交,并作为数据库的永久组成部分。否则就想要回滚或者取消,对数据做的更改需要被清除。只用具备ACID属性才能被称为事务。
- 1.原子性:对数据的更改要么全部执行,要么全部不执行。
- 2.一致性:事务执行结束之后所有数据都保持一致状态,保持数据的完整性和数据结构的一正确性。
- 3.隔离性,也称为可串行性,并发事务的执行必须与其他并发事务的执行修改隔离。互相不能看见执行的中间状态。
- 4.持久性:对系统的更改是永久的,该修改即便系统出现故障也应一直保持。
- 2 事务的三种运行模式:
- 1.自动提交的事务:每一条单独的sql语句都是一个事务。
- 2.显式提交的事务:以BEGIN TRANSACTION语句显式的开始,以COMMIT或者ROLLBACK显式结束。
- 3.隐式事务:上一个事务完成时新事物隐式启动,但也是BEGIN TRANSACTION语句显式的开始,以COMMIT或者ROLLBACK显式结束。还有一种批处理级事务,没有提交时由SQL Server自动回滚。
22系统进程通信的方式
- 1.管道(pipe):一种半双工通信模式,数据只能单向流动,且其数据只能在具备亲缘关系的进程之间流动,这种亲缘关系通常指父子进程。
- 2.命名管道(named pipe):也是一种半双工的通信模式,但其允许不具备亲缘关系的进程进行通信。
- 3.信号量(semophore):通常作为进程之间或同一进程不同线程间的同步手段,通常是一个计数器,控制对共享资源的访问。也常作为一种锁机制,避免多个进程同时访问共享资源。
- 4.消息队列(message queue):消息的链表。克服了信号量信号量的传输数据量小,管道只能承载无格式数据和管道的缓冲区受限的缺陷。
- 5.信号(signal):用于通知进程某个事件已经发生。
- 6.共享内存(shared memory):映射一段可以被其他进程访问的内存。由一个线程创建,多个进程访问专为进程通信效率低而设计,通常与其他通信机制配合使用,例如信号量机制。实现进程间的同步和通信。
- 7.套接字(socket):与其他进程通信不一样的地方是:它可以用于与其他不同机器进程间的通信。
23. HTTP与HTTPS的区别
- 1.what?
- 1.1HTTP协议用于客户端浏览器与服务器之间通信,它以明文方式发送内容,不提供任何方式的数据加密。如果攻击者截取了通信数据,将很容易读懂其中的信息。因此不适用于传送一些敏感信息:比如所银行卡号,密码等支付信息。
- 1.1为了解决这一缺陷,需要采用另一种协议:安全套阶层超文本传输协议HTTPS,也称为HTTP协议安全版。为了数据的传输安全,HTTPS在HTTP协议的基础上加入了SSL协议(网景公司设计)。SSL协议依靠证书来验证服务器的身份,并为双方通信提供加密。
- 2.difference?
- 2.1 https需要申请证书,一般免费的证书很少,因此会产生一定的费用
- 2.2 前者是通过明文通信,后者通过SSL加密传输。
- 2.3 两者采用不同的连接方式,端口号也不同,前者是80,后者是443.
- 2.4 前者连接简单且连接无状态,后者提供身份验证和加密传送。相比下后者更安全。
- 3.how?
- 3.1客户端通过URL访问服务器,要求建立SSL连接。
- 3.2 web服务器接收到请求之后,会将网站的证书信息(包括公匙)传送一份给客户端。
- 3.3 两者协商SSL连接等级,也就是信息加密等级。
- 3.4 客户端根据双方同意的安全等级,建立会话密匙,并使用网站的公匙将密匙加密传送给网站。
- 3.5 web服务器使用私匙解密出会话密匙。
-
3.6 服务器使用密匙加密和客户端之间的通信。
24.Servlet生命周期
-
- 加载:Servlet容器被启动时会通过类加载器加载相关class文件。
-
- 创建:在创建过程中若没有在web.xml中配置load-on-startup,则在第一次访问Servlet是才会创建其实例,否则若load-on-startup被配置为大于1时,将在Servlet容器被启动的同时初始化Servlet实例。
- 3.初始化:只会被执行一次:在Servlet被实例化初始化。
- 4.处理客户端请求:调用service()方法处理用户请求。
- 5.卸载:调用destroy()方法销毁servlet实例,随后垃圾回收器将回收该实例。
25.单例模式
-
- 饿汉式:
/**
* 饿汉式实现单例模式
* 利用静态static的方式进行实例化,在类被加载时就会创建实例。
*/
public class Singleton {
private static Singleton instance = new Singleton();//在类加载时实例单例对象
private Singleton() {}//私有的构造器
public static Singleton getInstance() {//返回一个实例对象
return instance;
}
-
- 懒汉式:这种方法的实现,效率不高,因为该方法定义为同步的方法。
/**
* 在被第一次引用时才去创建对象。
* 懒汉式实现单例模式
*/
public class Singleton {
private static Singleton instance;//创建私有的静态变量
private Singleton() {//私有的构造函数
}
// synchronized方法,多线程情况下保证单例对象唯一
public static synchronized Singleton getInstance() {
//如果实例对象为空,就重新去实例化
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
- 3.双重锁实现的单例模式double check
/**
* DCL实现单例模式
* 资源的利用率较高,在需要的时候去初始化实例,
* 而且可以保证线程的安全,该方法没有去进行同步锁,效率比较好。
*/
public class Singleton {
private static valotile Singleton instance = null;//这里要加入valotile关键字,避免指令重排序, 可能先赋值但是没有分配内存
private Singleton() {
}
public static Singleton getInstance() {
// 两层判空,第一层是为了避免不必要的同步
// 第二层是为了在null的情况下创建实例
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
26 设计模式六大原则:
- 1.单一原则:控制类的粒度大小,为了提高复用性,同一个类不能承担太多的职责,就一个类而言:应只有一个引起它变化的原因。
- 2.开闭原则:一个软件实体应对扩展开放,对修改关闭。即软件实体应该在不修改原有代码的基础上进行扩展。(尽量采用抽象化对系统进行重构)
- 3.里氏替换原则:使用引用基类的地方应能够透明的使用其子类的对象。(在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。)
- 4.依赖倒转原则::抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程。实现依赖倒转原则时,需要针对抽象层编程,而将具体类的对象通过依赖注入(DependencyInjection, DI)的方式注入到其他对象中,依赖注入是指当一个对象要与其他对象发生依赖关系时,通过抽象来注入所依赖的对象。
-
- 接口隔离原则:使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。一个接口应该承担一种相对独立的角色,不干不该干的事,该干的事都要干。接口仅仅提供客户端需要的行为,客户端不需要的行为则隐藏起来,应当为客户端提供尽可能小的单独的接口,而不要提供大的总接口。
- 6.迪米特原则(最少知识原则):一个软件实体应当尽可能少地与其他实体发生相互作用。降低系统的耦合度,使类与类之间保持松散的耦合关系。(不要和“陌生人”说话、而只与你的直接朋友通信)
27.XML和JSON优缺点
- 1.xml的优点:
- 1.1 结构简单统一。
- 1.2 易于与其他系统进行通信。
- 1.3 可读性高。
- 2.xml的缺点:
- 2.1 文件庞大,层次复杂。占传输带宽。
- 2.2 需要花大量代码解析xml,导致不易维护。
- 2.3 解析xml耗时占资源。
- 3.json的优点:
- 3.1 格式简单,易于书写,经过压缩后传输占用带宽小。
- 3.2 易于解析。使用eval()方法即可进行JSON数据的读写。
- 4.json的缺点:
- 1.没有xml的推广那么深入人心,也没有xml那么通用。
- 2.可读性较低。
- 3.在webservice中的使用还处于初级阶段。
28.XML文件读取的办法
-
1.DOM生成与解析:
- 3.3 支持多语言,易于服务端解析。
- 3.3 PHP服务端对象,数组能直接生成JSON格式,便于客户端读写。
- 3.4 解析代码简单,代码量小,提高开发效率,且易于维护。
28. 四种读取XML文件读取的主流办法
- 一.介绍及优缺点分析:
- 1.有哪四种:DOM,SAX,JDOM,DOM4J.
- 2.介绍:
- a.DOM:DOM是用于与平台和语言无关的方式表示XML文档的官方W3C标准。DOM是以层次结构组织的节点或信息片段的集合。这个层次结构允许开发人员在DOM树中寻找特定的信息。分析该结构通常需要加载整个文档或构建层次结构,随后才能做某些操作。由于它是基于信息层次的,因此DOM通常被认为是基于树或基于对象的。
- 优点:
- ①允许应用程序对结构和数据做更改。
- ②数据的访问是双向的,可以在任意时刻在树中上下导航。获取和操作任意部分的数据。
- 缺点:
- ①需要加载这个XML文档来构造层次结构,消耗资源大。
- 优点:
- b.SAX(Simple API for XML)
- 优点:
- ①不需要等待所有数据被加载都被处理,分析就能够开始(何时开始?- 机动性)
- ②只在读取数据时保存数据,不需要保存在内存中(内存需求?- 节约内存)
- ③满足某个条件即停止解析,不需要解析整个文档(只能解析整个文档吗?- 灵活的条件设置)
- ④效率和性能比较高,能解析大于系统内存的文档(效率如何?)
- 缺点:
- ①需要自定义Tag处理逻辑,比如维护父子关系。文档复杂时程序相应复杂(难编码)
- ②单向导航,无法定位文档的层次。难以访问同一文档不同部分数据,不支持XPath。
- 优点:
- c.JDOM(Java-based Document Object Model):
- 1.介绍:
- ①第一个java特定模型,简化了与XML的交互并且比DOM更快。
- ②JDOM和DOM的两方面不同:
Ⅰ:使用具体类而不是用接口,虽简化了API但也降低了灵活性。
Ⅱ:API大量使用Collections类简化了java开发者的使用。 - ③JDOM的目的:开发的高效率(花20%以下的精力解决80%以上的java/xml问题),而且更易于理解。
- ④Ⅰ.不包含解析器,它使用SAX2解析器解析和验证XML输入。Ⅱ.但它有转换器可将JDOM表示为SAX2事件流、DOM模型和XML文本文档。Ⅲ.Apache许可证变体下发布的的开源代码。
- 优点:
- ①使用具体类而非接口,简化DOM的API。
- ②大量使用java集合类,方便java开发人员。
- 缺点:
- ①灵活性差。
- ②性能差。
- 1.介绍:
- d.DOM4J(Document Object Model for Java)
- 1.介绍:JDOM的智能分支。但合并了超出基本XML文档基本表示的功能。包括XPath支持、XMLSchama、大文档或流文档基于事件的处理、提供构建文档表示的选项、通过DOM4J API和标准DOM接口具备并行访问的功能。而且还在持续开发中。
- ①使用接口和抽象基本类方法支持这些功能。大量使用Collections类但也提供一些替代方法允许以更高的性能的更直接的编码方式。虽付出了使API复杂的代价,却提供了更多的灵活性。
- ②与JDOM相同的目标:针对java开发者的直观性和易用性。致力于提供更完整地解决方案。
- ③ 性能优异,功能强大,且极端易用。同时还开放源代码。非常流行,甚至Sun公司的JAXM也使用了DOM4J.
- 优点:
- ① 大量提供java集合类,方便java开发者。同时提供了提高性能的替代方法。
- ②支持XPath
- ③性能优异,功能强大,且极端易用。同时还开放源代码。
- a.DOM:DOM是用于与平台和语言无关的方式表示XML文档的官方W3C标准。DOM是以层次结构组织的节点或信息片段的集合。这个层次结构允许开发人员在DOM树中寻找特定的信息。分析该结构通常需要加载整个文档或构建层次结构,随后才能做某些操作。由于它是基于信息层次的,因此DOM通常被认为是基于树或基于对象的。
- 二.比较:
- 1.DOM4J性能最好:连Hibernate也是用DOM4J来解析XML配置文件。因此不考虑移植性,DOM4J优先选用。
- 2.JDOM和DOM性能不佳,但可移植:小文档可以选择JDOM和DOM。而DOM是相当多XML标准的标准,支持多种编程语言。
- 3.SAX的事件驱动较好:需要及时处理而不保存数据则优选SAX。
29.如何防止SQL注入
- 1.限制用户数据库操作权限:仅提供用户满足其工作的最低权限。
- 2.检查输入是否符合期望的数据格式:比如正则表达式过滤。
- 3.对进入数据库的特殊字符(\、<、&、*等)进行转义处理,或编码转换。
- 4.查询语句使用数据库提供的参数化查询接口:即不直接不直接拼接SQL。如使用database/sql里面的查询函数Prepare和Query,或者Exec(query string, args ...interface{})。
- 5.应用发布之前使用SQL注入检查工具检测并及时修补漏洞:一些开源工具如sqlmap,SQLninja等。
- 6.避免应用打印SQL错误信息:比如类型错误,字段不匹配。这将导致暴露代码中的sql语句。
- 7.使用PreparedStatement代替statement执行sql语句。
30.数据库事务
- Ⅰ.脏读:一个事务处理过程中读取另一个没有提交事务的数据。
- 1.a转200块给b,b的钱多了200块,a的钱还没扣200就通知b来看,b一看自己的钱是多了200.但是a不提交事务导致数据库回滚。b在看的话会看到a刚才转的钱没了.
- Ⅱ.不可重复读:由于查询隔离查询的数据被另一个事务修改并提交了。
- 1.事务T1读取某数据后,T2立马修改数据并提交。T1再次读取返回不同的值。就好像小孩偷吃糖果。
- 2.脏读与不可重复读的区别:前者是一个是事务读取了另一个事务没有提交的脏数据.后者是事务读取了前一个事务提交了的数据.
- Ⅲ.虚度(幻读):事务非独立执行时的一种假象.
- 1.事务T1对数据库中某表某字段的所有列做了从'1'到'2'的设定.而假如此时事务T2再次向该表插入一条数据而其中该字段仍然为'1'.事务T1再次查看时发现"怎么有一条没改变?".就好像吉米逗汤姆玩儿.
- 虚读与不可重复读的比较:两者的相同点在于都是读取了已经提交的事务(不同于脏读).不同的是不可重复读读取的是某个数据项(字段).而虚读读取的则是批量整体.(比如数据条数)
- Ⅳ.MySQL提供的四种隔离级别:
- 1.Read Uncommitted.
- 2.Read Committed.
- 3.Repeated Read.
- a.MySQL提供的默认隔离级别.
- 4.Serializable.
- a.以锁住整个表的方式(类似于锁住整个表,使其他线程在锁外等候.)
- Ⅴ.Oracle只支持2.4,默认为2.
31.Java多线程之锁优化策略
- Ⅰ.减少锁持有时间.
- 1.减少同步代码数量.
- Ⅱ.减少细粒度.
- 1.使用Concurrent容器例如ConcurrentHashMap对Segment加锁而不是整个map.
- Ⅲ.锁分离.
- 1.根据同步性质,将锁划分为读锁或写锁.读锁可以不互斥.从而提高并发能力.
- Ⅳ.锁粗化.
- 1.对不连续同步代码块一次性加锁解锁,将锁的范围扩大.减少频繁加锁解锁小号的时间.即便锁的持有时间增多了,但总体性能却有所优化.
- Ⅴ锁消除.
- 1.锁消除是编译器所做的事:根据代码逃逸技术,如果经判断一段代码中,堆上的数据不会逃逸出当前线程(也即不会影响到线程空间外的数据),那么就认为当前代码是线程安全的,不需要同步加锁.
- Ⅵ.JVM采用的锁优化策略.
- 1.偏向锁:锁对象偏向于当前获得到它的线程.若接下来没有其他线程请求获取该锁.那么持有这把锁的线程将不再需要进行同步操作.(也即该线程执行同步代码块时不需要执行lock()和unlock()了,直接执行代码即可).直到另一个线程申请该锁.当前线程的偏向模式才结束,让出该锁.
- 2.轻量级锁:synchronized的底层使用监视器monitor来控制的.而monitorenter和monitorexit原语依赖操作系统的互斥mutex来实现.互斥导致线程挂起后,在短时间之内却又要将重新调度回原线程,这将导致资源浪费.而轻量级锁(LightWeight Locking)采用CPU原语CAS(Compare-Ans-Swap)来实现.它尝试在进入互斥之前进行补救,减少多线程进入互斥的几率.如果采用偏向锁失败之后,系统会获取轻量级锁.使用CAS来加锁.如果获取轻量级锁也失败,才会调用操作系统级别的重量级锁synchronized来加锁.
- 3.自旋锁.如果当前线程获取被锁,而该锁被占用.则当前锁将执行忙循环(自旋).看持有锁的线程是否会在短时间之内释放锁.如果自选之后还没有获得锁,才会进入阻塞状态.
- 3.1 自适应自旋:自旋的时间是同一线程上一次自旋获得锁的耗时.如果对于这个锁,很少达到自旋目的.就不自旋了,免得浪费CPU资源.
- 4.过程:为了尽量避免使用重量级锁(操作系统层面的互斥).JVM会首先尝试使用偏向锁.尽量不lock().获取偏向锁失败,JVM尝试使用轻量级锁,使用CAS操作获取锁.如果获取失败,说明还存在竞争,但也有可能很快获得锁:就会尝试使用自选锁.让线程做几次空循环每次循环都尝试获得锁.如果自旋锁都失败了,就升级为重量级锁.
32.10亿个数中找出最大的10000个数(top K问题)
33.Maven生命周期
-
Ⅰ.Maven的三套独立生命周期
- 1.Clean Lifecycle:执行构建之前进行一些清理工作.
- 1.1:pre-clean,clean,post-clean
- 2.Default Lifecycle:构建的核心部分:编译,测试,打包,部署.
- 3.Site Lifecycle:生成项目报告,生成站点,发布站点.
- 3.1 pre-site:生成项目站点之前需要完成的工作.
- 3.2 site:生成项目站点文档.
- 3.3 post-site:生成项目站点后需要完成的工作.
-3.4 site-deploy:将项目站点发布到服务器.
- 1.Clean Lifecycle:执行构建之前进行一些清理工作.
-
Ⅱ.Default Lifecycle:
- 2.1 validate:验证工程是否正确:所有需要的资源是否可用.
- 2.2 complie:编译项目源代码.
- 2.3 test:选用合适的单元框架来测试已编译的源代码.
- 2.4 package:将已编译的代码打包成可以发布的格式,比如jar.
- 2.5 intgration-test:如果可以,将打包结果发布到一个能进行集成测试的环境中去.
- 2.6 vertify:运行中检查:验证包是否达到质量标准.
- 2.7 install:将包安装到本地仓库,使其可被其他工程依赖使用.
- 2.8 Deploy:在集成或发布环境下执行.将最终版本的包拷贝到远程仓库 remote repository,使得其他的开发者或者工程可以共享使用.
34. 深入浅出数据库索引原理
- Ⅰ.索引数据结构
-
- 主流的RDBMS将平衡树作为数据表默认数据结构.少数将哈希桶作为索引数据结构.平衡树是一种b树,或b+树而非二叉树.
- 2.给数据表增加主键将使其在磁盘上的数据结构从整齐排列(无序)变成平衡树.此时整个表都会变成索引,即聚集索引.因此一个表只能有一个一个聚集索引.
-
- Ⅱ.建立索引的举例
- 1.数据表中有1亿条数据.如果进行顺序匹配,其时间复杂度为O(n).有几个问题:CPU运算能力不足,内存无法一次性容纳1亿条数据,磁盘IO次数多,处理速度极慢.
- 2.如果建立索引:
- 2.1 优点:时间复杂度由O(n)将至O(log n)(n为数据量总数,底数为平衡树分叉数,结果为数的层次高度).时间复杂度由亿级将至个位数,性能有了极大地提升
- 2.2 缺点:写入速度降低.每次增删改都会改变索引节点数据内容改变树结构.DBMS必须重新梳理树结构保证正确性.导致性能降低.
- Ⅲ.非聚集索引:索引树中各节点来自于表的索引字段.数据改变时,DBMS需要一直维护索引的正确性.如果给表的多个字段加索引,将出现多个独立的索引结构,每个非聚集索引之间没有关联.
- 1.缺点:每给一个字段新建一个索引,字段中的值都会被copy出来用于建立索引.因此会增加表的体积占用磁盘存储空间.
- 2.聚集与非聚集的区别:通过聚集索引可以查找到数据.而通过非聚集索引可以查询到记录所对应的主键,在利用主键到聚集索引中查询所需的数据.不管通过何种方式查询表,最终都会利用主键通过聚集索引定位数据.聚集索引(主键)是通往真实数据的唯一路径
- 3.【例外-覆盖索引】:不使用聚集索引即可查询到所需数据.也称复合索引或多字段索引.多个字段都会用于构建索引.即如果查询覆盖索引时发现索引中已有所需查询的字段,此时将不会在利用主键去查询聚集索引.省去两步从而提高了效率.
35.哪些情况下索引会失效?
- Ⅰ.当条件中有OR时,即便有条件带索引也不会使用(这也是避免使用OR的原因).但如果又想用OR又想使用索引,解决方法是给OR条件中每列都加上索引
- Ⅱ.对于多列索引,如果不是使用的第一部分,就不会使用索引.
- Ⅲ.like查询以%开头.
- Ⅳ.如果列数据类型为字符串,那么在条件中一定要将数据使用引号引用起来,否则也不会使用索引.
- Ⅴ.如果DBMS预估全表查询比用索引查询速度更快,也不会使用索引.
- Ⅵ.查看索引使用状况:
show status like 'Handler_read%';
//handler_read_key --->该值越高越好,反应使用索引查询到的次数
//handler_read_rnd_next--->值越高表示越低效.
36. 数据库SQL优化大总结之 百万级数据库优化方案
- 1.尽量避免全表扫描,尽量在where即order by所涉及的列上建立索引.
-
- 尽量避免在where子句中对字段进行判null,因为这将导致引擎放弃索引而进行全表扫描.char(n)型设立就将占据n个字符空间.varchar是变长字段,null将不占据空间.
- 3.尽量避免在where中使用!=或<>操作符,这将导致引擎放弃使用索引而进行全表扫描.
- 4.尽量避免在where子句中使用OR,因为若有一个字段没有索引.将导致放弃使用索引方式查找而改用全表扫描.使用union all解决.
- 5.慎用in和not in,改用between或exists解决.
- 6.慎用like "%",这将导致全表扫描.可改用全表检索来提高效率.
- 7.where子句中使用参数(如@num)将导致使用全表扫描.因为SQL只有在运行时才会解析局部变量.而优化程序却不能将访问计划的选择推迟到运行时.它必须在编译阶段就进行抉择.可编译时建立访问计划时,此时变量值却还是未知的,这将导致它无法作为索引选择的输入项.解决办法是强制查询时使用索引.
- 8.同样的道理:应尽量避免在where子句中对字段进行表达式操作.
- 9.应尽量避免在where子句中对字段进行函数操作.
- 10.尽量避免在where子句"="左边进行表达式运算,函数运算,算术运算.这可能会导致系统无法正确使用索引.
- 11.在使用索引字段作为where条件时.如果该索引是复合索引.应使用该复合索引第一个字段作为条件,且其后的字段条件顺序应与索引顺序保持一致.唯有这样才能保证系统使用该索引加快查询.
- 12.拒绝使用一些没有意义的查询.如需要生成一个空表结构:
select col1,col2 into #t from t where 1=0;--这类代码虽不会返回结果集,却会消耗系统资源,应该为:
create table #t(...);
- 13.使用update语句时如果只修改1,2个字段,就不要修改更多字段.因为这将导致引起明显的性能消耗,还会写更多的日志.
- 14.对于多张大数量表(几百条就很大了)的表的join,应先分页在join.否则将导致逻辑读致使性能消耗.
- 15.杜绝没有业务意义的操作,如:select count(*) from table;且会引起全表扫描.
- 16.索引数应不大于6,因为索引在带来查询速度提升的同时也将导致insert,update速度变慢,维护索引也将带来性能的消耗.
- 17.尽量避免更新clustered索引数据列.因为它的顺序就是记录的物理存储顺序.该列的改变将导致表顺序的调整.消耗大量资源.一旦发现系统需要频繁更新clustered索引数据列,就应该反思是否应需要该字段取消设立clustered数据列.
- 18.对只含数值信息的字段应避免设计为字符型.优选数字型.否则将导致查询和连接的性能下降,内存的开销增大.这是因为引擎在处理查询和连接时会逐字比较每个字符,而数字只需比较一次.
- 19.尽可能使用varchar/nvarchar代替char/nchar.有两个原因:1)节约内存空间.2)检索短字符搜索效率更高.
- 20.不要使用select * ,不要返回无用字段.
- 21.尽量使用表变量代替临时表.
- 22.避免频繁创建和删除临时表,减少系统资源消耗.当需要重复引用大型表或者常用表中的某个数据集时可以采用临时表.但对于一次性时间,最好使用导出表.
- 23.新建临时表时,如果一次性插入数据量很大,可以考虑使用select into代替create table,从而避免产生大量log.提高速度.如果数据量不大.为了缓和系统表资源,应该先create table,在insert.
- 24.如果用到了临时表,那么在存储过程的最后一定要将临时表显式删除.先truncate table,在drop table,这个过程可以防止系统表长时间锁定.
- 25.尽量避免使用游标,因为游标的效率很差,当游标操作的数据量较大(例如超过1W条时),应考虑改写了.
- 26.在使用临时表或者游标时,应尽量寻找基于集的解决方案.通常基于集的解决方案很有效.
- 27.与临时表一样,游标并非不可用.对小型数据集使用FAST_FORWORD游标通常优于其他逐行处理方法.在结果集中包含"合计"的例程中通常比游标执行的速度要快.如果开发的时间允许,两者都应该尝试一下,看哪个效果更好.
- 28.在所有的存储过程和触发器的开始出设置SET NOCOUNT ON,在结束时设置SET NOCOUNT OFF.因为不需要在执行存储过程和触发器的每个语句之后想客户端发送DONE_IN_PROC消息.
- 29.尽量避免大的事务操作.以提高并发能力.
- 30.避免向客户端发送大量数据.如果数据量过大,应反思需求是否合理.
37. Spring中Bean的五个作用域
- Ⅰ.五个作用域:
- 1.singleton:单例模式.使用它定义的Bean将只有一个实例.spring创建applicationContext容器的时候.spring会预初始化所有该作用域实例.但使用lazy-init可以避免预处理.
- 2.prototype:原型模式.每次调用容器的getBean()方法都将产生一个新的实例.
- 3.request:每次发起HTTP请求调用getBean()方法,都将产生新实例.只有在web应用中才有效.与prototype还有不同在于:在创建实例之后在接下来的管理中spring依然会监听.
- 4.session:每个HTTP Session 都可以产生一个新的实例且互不影响.只在web应用
中有效.全局web域,类似于servlet中application.
- Ⅱ.使用建议:
- 1.常用singleton和prototype模式.singleton模式的Bean,每次请求该Bean都会获得相同的实例.容器会追踪该实例的状态和维护其生命周期行为.而prototype类型的Bean,Spring容器只会使用new关键字创建实例.创建成功后容器不会追踪实例,亦不会维护该实例.
- 2.spring默认使用singleton作用域.因为若使用prototype作为作用域Java创建实例时会进行内存申请,销毁实例时会进行垃圾回收.这将导致系统开销增大.而singleton实例一旦创建成功即可重复使用.
- Ⅲ.spring的controller是单例的还是多例的?
-
- 单例的.只要在controller中不定义属性.使用singleton也可以保证线程安全.但若非使用singleton却又有非static属性.可以采用
- 1.方法一
-
- 2.【方法二】:定义非静态变量时,增加注解@Scope("prototype"),将其设置为多例模式.
38.Java中的定时任务
- 1.利用Sleep特性(休眠)
- 2.time和timeTask(定时器)
- 3.利用ScheduledExecutorService将定时任务与线程池功能结合使用.
39.TCP和UDP相关
- Ⅰ.TCP通过什么方式提供可靠通信.
- 1.超时重传:若发出报文段后没有收到及时的确认,会重发.
- 2.数据包校验:校验首部数据和.
- 3.重排序.
- 4.流量控制,避免缓冲区溢出.
- 5.快重传和快恢复.
- 6.TCP会将数据截取为合适的长度.
- Ⅱ.TCP与UDP的区别
- 1.基于连接与无连接.
- 2.UDP面向报文的,没有拥塞控制.适合多媒体通信,比如即时聊天,支持1对1,1对多,多对多.TCP只能1对1.
- 3.对系统资源的要求(TCP要求多)
- 4.传输模式:UDP数据报模式.TCP流模式
- 5.可靠与不可靠.
- Ⅲ.UDP的应用场景(TCP:文件传输,邮件收发)
- 1.面向数据报方式.
- 2.网络数据大多是短消息.
- 3.拥有大量客户端.
- 4.对数据安全性无特殊需求.
- 5.网络负担比较重.但要求响应迅速.
40. 内部类访问局部变量的时候,为什么变量必须加上final修饰
- 1.我们在内部类中直接控制局部变量和引用,实际是通过构造函数中传入变量副本实现的.但java为了维护自身的封装风格.要求访问访问的变量为final类型:当变量为普通变量则数值相同且为常量;为引用类型就只能指向已确定的对象.借此保证内外统一.
41.为什么IP协议也能够进行数据的不可靠传输,还需要UDP?
- 1.需要端口号来进行应用程序之间的区分.
- 2.IP校验只能校验IP报头.而不是整个数据报.整个数据报的校验需要在传输层完成.如果出错了,就需要将出错的数据报丢弃.UDP校验和就具备传输层校验的能力.虽然它不具备纠错的能力.但可以将出错报丢弃.
42.进程通信中管道和共享内存谁的速度快?
- 1.管道:写进程往管道写入数据,读进程从管道读取数据.
- 2.通过将内存空间映射到进程地址空间,不需要执行任何进入系统内核的系统调用.因此共享内存更节约时间.
43.深入剖析Java中的装箱和拆箱
- 1.通过javap 反编译命名得到结论:装箱过程是调用包装器的valueOf()方法实现的.拆箱是调用包装器的xxxValue()方法实现的.
44. 过期的suspend()挂起、resume()继续执行线程
- 1.不推荐使用的原因:suspend()期间,线程不释放锁,导致其他线程无法获取锁而被阻塞.直到调用resume(),被挂起的线程才会继续.被阻塞的线程才能恢复.但假如resume()出现在suspend()之前.线程将一直处于被挂起的状态.同时一只占用锁.从而导致死锁.
45. JQuery实现——黑客帝国代码雨效果
- 真好看,mark一下...
46.Hash算法
- Ⅰ.Hash算法的查找步骤.
- 1.使用Hash算法将键值映射成索引.
- 2.处理Hash冲突.
- Ⅱ.Hash构造函数的方法.
- 1.直接定址法:
- 1.1:H(k)=k 或 H(k)=a×k+b ; (其中a,b为常数)
- 1.2.【优势】不同的关键字不会发生冲突.【逆势】:现实生活中连续的关键字很少,若关键字不连续将造成空间的大量浪费.因此其适应性不强.
- 2.数值分析法:
- 1.取数值关键字中取值较均匀的数位作为Hash地址的方法.适用于能预估全体关键字中每一位上数字出现的频度.
- 3.折叠法:
- 1.分为移位折叠和边界折叠.适用于关键字数字位特别多且每一位上数字分布大致均匀的情况.
- 4.平方取中法:
-
- H(key)="key"^2的中间几位.该方法的原理为通过平方来扩大差别.平方值和每一位都有关.对不同的关键字得到的哈希函数值不易发生冲突.产生的地址也比较均匀.
- 2.使用于关键字中的每一位都有某些数字出现频度很高的情况.
-
- 5.基数转换法:
- 1.将进制数转换为其他进制后取其中若干位作为Hash值.
- 6.除留余数法,随机数法,随机乘数法,字符串数值Hash法,旋转法.
- 1.直接定址法:
- Ⅲ.Hash冲突处理方法.(冲突只可较少不可消除)
- 1.开放地址法(再散列法):线性探测,二次探测,伪随机.该方法容易聚集.
- 2.再Hash法.不易聚集但增加了计算时间.
- 3.链地址法
- 4.建立公共溢出区.
47.Minor GC与Full GC分别在什么时候发生?
- Ⅰ.区分:
- 1.Minor GC:发生在新生代.回收频繁速度快.
- 2.Major GC/Full GC:发生在老年代.Major GC常伴随MinorGC.速度慢.
- Ⅱ.时机:
- 1.Minor GC:无法为新对象分配空间时.
- 2.Full GC:
- 2.1 老年代无法分配内存.
- 2.2 发生Minor GC时也有可能触发Full GC.因为老年代要对年轻代进行担保.但进行垃圾回收之前无法获知会有多少对象存活.老年代只好采用动态估算的方法来估算自己需要担保多少内存空间:上一次回收晋升到老年代的平均值.此时若发生Minor GC后存活的对象剧增超过估算值,将发生Full GC.