本文出自
代码大湿
代码大湿

有段时间没有更新新文章了,接下来想把文章的更新速度放慢点,主要是想写出更高质量的文章,最近收录了多年面试的经典题目,包括答案,本系列会持续更新。


1 线程和进程的区别

1	资源占用:进程是系统资源分配的基本单位,进程拥有自己独立的内存空间,所属同一进程的各个线程共享进程的内存空间。线程的上下文切换更快。

2	调度和运行:线程是进程的实体,是系统调度的基本单位,线程的调度要依赖进程,不能单独运行。

2 谈谈Vector和ArrayList,LinkedList

相同:
都是实现了List接口,内部都是使用的动态数组,元素是有序的,可以根据索引来访问元素。

不同:
1  Vector是线程安全的,ArrayList和LinkedList是非线程安全的,所以ArrayLsit的执行的效率要高于Vector。
2  Vector当需要增加长度的时候,会增加原来长度的1倍,而让ArayList会增加原来的一半。
3  Vector设置了增长空间的方法,ArrayList没有设置此方法。
4  LinkedList是使用的双向链表,继承了Deque接口。

这2者和LinkedList的优缺点:
很明显,LinkedList的优点是可以实现元素的插入和删除操作。而Vector和ArrayList可以实现快速的元素的随机访问。


3 谈谈HashMap和HashTable

1  HashTable是线程安全的,HashMap是线程非安全的,HashMap效率会比HashTable高。
2  HashTable不能有null,HashMap可以用null做key和value。
3  2者都可以使用iterator遍历,而HashTable还可以使用enumeration。
4  HashTable继承比较老的Dictionary,HashMap继承AbstractMap。尽量使用ConcurrentHashMap替换HashTable,因为前者效率更高。
5  HashTable的初始容量是11,扩容的方式是2*old+1。而HashMap初始容量是11,而且一定是2的倍数。

4 String,StringBuilder和StringBuffer

1  String是final修饰的字符串常量,对象内容不可变。后2者都是字符串变量,内容可以改变。
2  StringBuilder是非线程安全的,StringBuffer是线程安全的。所以StringBuilder的执行效率要高于StringBuffer。
3  StringBuilder和StringBuffer都是继承自AbstractStringBuilder。

5 sleep()和wait()方法

1  sleep是Thread的方法,wait是Object的方法。
2  sleep会暂停线程的执行,但是不会释放锁,到了指定时间会自动释放,,而wait会释放锁,让线程进入等待锁定池。
3  sleep需要捕获异常,而wait不用。
4  sleep可以在任何地方使用,而wait只能在同步块或者同步方法中使用。

6 UDP和TCP

1  TCP传输数据之前需要建立连接,UDP是传送数据包,不需要建立连接。
2  TCP提供可靠的传输,而且利用滑动窗口技术还提供差错检测,数据重传等服务。
3  TCP是传输的二进制字节流,UDP传输数据包,而且UDP不会提供拥塞控制,当数据传输量很大的时候,并不会降低发送端的传输速率。
4  TCP提供的是端到端的服务,UDP提供一对多,多对一,多对多的服务
5  TCP数据包的消耗比较大,而UDP数据包消耗会很小。

7 类的加载机制

类的加载顺序是:

加载->验证->准备->解析->初始化->使用->卸载
其中前5个阶段是类的加载阶段。

加载:

1  获取classes文件(通过类的全限定名)或者网络中的二进制字节流。
2  将二进制的静态存储结构转换为方法区的动态存储结构。
3  在堆中生成Class对象,作为对方法区的访问接口。

验证:

主要验证二进制文件的格式是否有错误。

准备:

这个阶段为类的static变量分配内存,并对其赋予默认0值,只是针对static的类变量。如果是final和static同时修饰。此时就为其分配程序中指定的值。

解析:

将符号引用转换为直接引用。

初始化:

真正意义上执行程序中的代码。为变量赋予程序中指定的值。

8 gc回收算法

1  标记-清理:先标记存活的对象。然后将未标记的需要清理的对象清理掉,,效率低下,会产生内存碎片。
2  复制算法:将堆内存划分为2部分,将存活的正在使用的对象复制到另外一个内存区域,消除了内存碎片。
3  标记-整理:标记存活的对象,然后将存活的对象向堆内存的一边移动,消除了堆内存的内存碎片。
4  分代回收算法:将堆内存划分为,年轻代(Eden,Survivor from,Survivor to),年老代,永久代。然后根据不同内存区域中对象的生命周期来使用不同的回收算法。一般年轻代(因为存活对象少)使用复制算法(minor gc)。年老代使用标记-整理算法(major/full gc)。

9 gc回收器

Serial收集器一般是用在Client的虚拟机。有年轻代和年老代。

Serial:年轻代的垃圾回收器。使用复制算法。
Serial Old:年老代的收集器,使用标记整理算法。

Parallel收集器

Parallel Scanvage收集器:年轻代的收集器,使用复制算法。目标是获取最大的吞吐量。
Parallel Old收集器:年老代的收集器,使用标记-整理算法。

CMS收集器(concurrent mark-sweep)

用在服务器端的收集器。目标是获得最短的用户停顿时间。

g1收集器

最前沿科技的成果,但是内存布局和传统的内存布局不一样。

10 TCP的3次握手和4次挥手

TCP的建立的三次握手:

这里写图片描述

原始状态为Closed状态,需要建立连接的时候,
第一次握手

Client将数据包的SYN为置为1,序列号seq为J,将数据包发送服务server,此时Client的状态为SYN_SENT。

第二次握手

server接受数据包后,检查到SYN=1,知道client需要建立连接。server发送数据包,将SYN=1,seq=k,ACK=J+1	。server状态为SYN_RCVD。

第三次握手

Client收到数据包后,发送数据包,ACK=k+1。server收到数据后,检查ACK的值无误,连接建立。进入established。

TCP断开的四次挥手:

这里写图片描述

原始状态为established
第一次挥手

client发送FIN数据包。客户端进入FIN_WAIT_1。

第二次挥手

server收到数据包后。发送ACK确认包。server进入CLOSED_WAIT。client收到数据后检查ACK无误,client进入FIN_WAIT_2。

第三次挥手

server发送FIN数据包。server进入LAST_ACK。

第四次挥手
client收到数据包后发送ACK包,client进入TIME_WAIT。client等待2MSL后,如果server没有反应,则进入Closed状态。


11 B(B-)树和B+树

M阶B(B-)树有以下几点特性:

1	如果这棵树不是空树,根节点至少有2个子节点。
2	中间节点至少有ceil(M/2)个子节点。
3	非叶节点最多有M个子节点。
4	有k个关键字的节点有k+1个子节点。
5	所有叶子节点都在同一层。

这里写图片描述


12 数据库事务的隔离级别

数据库事物有4个隔离级别(以下级别依次提高)

READ UNCOMMITTED:读取未提交数据,此级别会造成脏读,不可重复读,幻读。
READ COMMITTED:读取提交数据,消除了脏读,但还是会有不可重复读,幻读。大部分数据库都是这个隔离级别。oracle,sqlserver
Repeatable read:重复读,消除了脏读和不可重复读。会有幻读。Mysql是这个隔离级别。
Serializable:最高隔离级别,消除了幻读。

13 数据库索引

数据库索引有聚集索引和非聚集索引。

聚集索引:聚集索引是表中的记录的物理顺序与索引的key的顺序相同,聚集索引是唯一索引,一个表只能有一个索引。相对于非聚集索引,聚集索引提供更快的查询速度。
非聚集索引:聚集索引是表中的记录的物理顺序与索引的key的顺序不相同。不是唯一索引。

14 JVM堆和栈

堆:解决程序的存储问题,存储运行时的对象,是所有线程共享的。
栈:解决运行问题,存储单个线程的本地变量,运行状态,和返回结果。线程运行结    束,栈也会随着消失。

15 JVM运行时方法区

JVM运行时将内存区域分为

1  程序计数器:是线程隔离的,只是线程下一条将要执行的指令的位置。
2  JVM栈:每个线程都有自己的虚拟机栈,主要存储线程的本地变量,自然是线程隔离的。
3  堆:存储程序中所有的对象,是所有线程可以共享的内存区域。
4  方法区:存储类的信息,类变量(static变量),是所有线程共享的。

16 JVM内存模型

JVM规定所有的变量都存储在主存中,而每个线程运行时都有自己的工作内存。每个线程不能自己操作主存,必须通过工作内存。一个线程不能直接访问其它线程的变量。

17 数据库范式(NF)

数据库范式有8个范式。通常我们设计数据库需要满足前面3个范式。

1NF	数据表的字段是原子的,不可再分。
2NF	在1NF的基础上,非主键列对主键是完全依赖,不存在非主属性对主键的部分依赖。
3NF 在2NF的基础上,非主键列对主键是直接依赖,不存在非主键列对主键是传递依赖。(如非主属性C依赖于非主属性B,非主属性B依赖于主键A)

18 数据库事务的4个特性

1	原子性:一个事务对数据的操作要么成功,要么失败。如果有异常,会回滚到事务操作数据之前的状态。
2	一致性:事务修改数据库之前和修改数据库之后的状态要保持一致。
3	持久性:既事务对数据库的操作是永久性的。
4	隔离性:多个事务之间的操作应当是隔离的。

19 内存分配策略

1	指针碰撞法:针对连续的内存空间,有内存分配的请求的时候,将指针指向一边。
2	空闲表法:针对不连续的内存空间,所有的空闲内存都记录在一个表中,当需要分配内存的时候,查询这个表,将满足大小的内存分配。

20 Java4种引用的类型

强引用:我们平时使用到的引用都是强引用,在gc回收内存的时候。会将不可达对象回收掉。
软引用:SoftReference<V>,在内存不足的时候会将软引用对象回收掉。
弱引用:WeakRerence<V>,gc回收的时候会将弱引用对象回收掉。
虚引用:PhantomRerence<V>,此引用不能引用到对象,在跟踪gc回收器的时候使用。

21 乐观锁和悲观锁

悲观锁:数据库事务获取数据之前,将数据加锁,别的线程要读取数据会blocking。
乐观锁:数据库事务获取数据不会加锁,但是更新数据的时候会检查是否有别的线程在此期间更新数据,如果有别的事务在修改数据,此事物会回滚,可以使用版本号等机制。乐观所适用于写操作很少的情况下。

22 脏读,不可重复读,幻读

1  脏读:读取到没有提交的数据。比如老张发现自己的银行账户收进了老板打来5000元,但是老板此时还为提交事物,老发发现打钱的数来那个有误,其实是2000。老板又撤销了事物。这是后老张的银行账户其实只有2000元。

2  不可重复读:比如老张的老婆在用老张的账户进行取款操作,而此时老张正在使用银行卡进行pos消费。当老张老婆查询到账户还有5000,但是在老张老婆取款前,老张pos消费了3000.然后老张老婆进行取款,会显示余额不足。

3  幻读:老张老婆在银行部门工作,查询了老张这个月的消费账单,而然后老张又pos消费了一笔。然后老张老婆打印账单会发现多了一条记录。

23 Stastement和PreparedStatement

Java中是这样使用两者的:
Statement st=connectiion.createStatement();
st.execuseQuery(sql);

PreparedStatement pst=connection.preparedStatement(sql);
pst.ecxcuseQuery();

程序中应该尽量用preparedStatement。优势如下:

1:可使用参数化查询。参数化查询的效率比凌乱的字符串追加的方式的效率更高。
2:会有预编译处理(jdbc引擎支持的前提),会将编译好的sql语句放进数据库系统,下次可以重新使用。对于相同查询,不同参数的查询,效率会很好。
3:可以防止大部分的sql注入攻击。

24 抽象类和接口

1	抽象类中可以有默认的方法实现,而接口不可有有方法的实现。
2	抽象类的方法的修饰符可以是public, private,protected.但是接口中方法只能是public(默认就是public ) 
3	抽象类可以定义普通变量。接口中的变量只能是public static final(默认)
4	继承抽象类后不可以继承其他类,实现接口后可以,继承其他类。
5	抽象类可已有构造方法,接口不行。

使用时机:
当需要有一些方法的默认实现的时候,就用抽象类。
当还有其他的父类需要继承的时候就必须用接口。

25 TCP的滑动窗口

点击我

26 消息队列的作用

1	实现解耦。
2	用作缓冲。
3	异步通信,送达保证。

27 Java IO用到的设计模式

IO用到的设计模式主要有装饰模式和适配器模式。
详情请点我

Java IO

28 Java IO VS NIO

1 IO是面对字节(字符)流的,NIO是面对缓冲区的。IO面对流意味着每次从流中读取一个或者更多字节,没有被缓冲到任何其它地方,数据不能前后移动。NIO面对缓冲区更具有灵活性,它将数据读取到一个缓冲区,可以在缓冲区中前后移动数据。
2 IO是阻塞模式的。NIO是非阻塞的。阻塞意味着每次读取数据的时候,一定要读取到数据,如果没有数据,此时线程不能做其它任何事情,直到等到有数据可读(数据完全写入)为止。NIO的非阻塞模式当没有数据可读的时候线程不会阻塞,会先去干其它事情,通常会去处理其它channel的读写。所以此时一个线程就可管理多个channel。

Java IO与NIO区别

29 单例模式

详细请点击我

//内部类实现

//单例模式

class Single{
	//将构造器变为私有
	private Single(){
		
	}
	//内部类
	private static class SingleHolder{
		private static final Single Instance=new Single();
	}
	public static Single getInstance(){
		return SingleHolder.Instance;
	}
}

30 java堆的参数

堆内存

-Xms:初始内存
-Xmx:最大堆内存

非堆内存

-XX:PermSize	非堆内存初始大小
-XX:MaxPermSize:非堆内存最大大小

31 volatile的作用

1	实现变量的可见性,让读取变量的线程及时读取到变量最新的值,禁止工作线程拷贝。
2	防止编译器的指令重排序。

32 BeanFactory和ApplicationContext的区别

1  BeanFactory是最基本的接口,ApplicationContext是前者的扩展。功能更加强大。
2  ApplicationContext扩展MessageSource来支持国际化功能。
3  ApplicationContext有事件监听空能。因为其支持ApplicationEvent和ApplicationListener。
4  ApplicationContext在容器加载的时候会初始化所有容器中的对象,BeanFactory会延迟加载,直到getBean的时候才会初始化对象。前者能更好的检查容器配置中的错误。
5  BeanFactory的实现有XmlBeanFactory。ApplicationContext的实现有XmlWebApplicationContext,FileSystemXmlApplicationContext,ClassPathXmlApplicationContext,
6  ApplicationContext扩展ResourceLoader(资源加载器)支持底层资源访问。

33 面向对象的设计原则

7大原则:

1  里氏替换原则,所有子类必须都能够代替父类。
2  依赖倒置原则,实现应该依赖与抽象,而不是具体
3  开闭原则,所有类应该对扩展开放,对修改关闭
4  单一职责原则,一个类应该专注与做一件事情。
5  迪米特原则,一个软件实体应该尽可能少得访问其它实体。
6  聚合原则,应该尽可能多得使用聚合或者复用,避免使用继承。
7  接口隔离原则,应该尽可能为客户提供单独的小的接口,而不是大的接口。

34 几种导致类加载的情况

1  使用new关键字,读取类的静态成员,设置类的静态成员值,调用类的静态方法,如果类没有被初始化,则要先初始化类。
2  使用java.lang.reflect中的方法进行反射调用的时候,如果类没有被初始化,则要先初始化类。
3  加载一个子类的时候,如果父类没有被加载,则要先加载父类。
4  JVM启动的时候,要先加载主类(带有main方法的类)、
5  一个java.lang.invoke.MethodHandler的实例的解析结果(结果是REF_getstatic,REF_putstatic,REF_invokestatic)的方法句柄所对应的类没有被初始化,则要先初始化此类。

35 css导入方式

1 在html标签中使用style属性

`<span style="color:blue">我是蓝色</span>`

2 直接在head中写css文件,style标签

<head>
	<style type="text/css">
		h1{color:red}
	</style>
</head>
<body>
	<h1>我是1号标题</h1>
</body>

3 将css文件单独写在一个文件中然后用link标签导入。

写好的一个css文件test.css。然后在html文件中。

<head>
	<link href="test.css" rel="stylesheet" type="text/css"></link>
</head>

36 集合框架的UML图

37 数据结构

点击我

38 二分查找算法

详细点击我

39 ConcurrentHashMap的原理

ConcurrentHashMap主要有3个对象,HashMap,Segment,HashEntry。
ConcurrentHashMap默认有16个Segment(段),一个段里面装的是HashMap的一部分Entry。操作特点:

put,get,remove操作:都是将对应的Segment加锁。读写某个的Segment中的Entry,并不影响其它Segment的操作,这是其增加Map性能的核心方法。
size方法会锁定整个表。

40 视图和表

视图就是一些sql语句的集合,是从数据表中提取的子集。
一般可以禁止用户访问数据库表,而以视图的方式呈现给用户,这样既可以保证数据表的安全,也可以让用户或者应用程序不受到数据库修改带来的影响。
2者区别:

1	视图不占用物理内存。表要占用物理内存。
2	视图是展现数据的窗口。表是数据内容。
3	我们可以对表进行修改,但是只能通过创建视图的语句来修改视图。

41 sessions和cookies

客户端第一次通过http协议访问服务器的时候,服务器会生成一些带有限制条件的key-value键值对,cookies保存在客户端,当下次同一客户端访问的时候,条件满足的时候,会将这些数据完整地带回服务器,sessions保存在服务器端。cookies保存在客户端浏览器内存中,访问服务器的时候会返回给服务器一个name叫做JSESSIONID的一个cookie。

42 ThreadPoolExecutor的及其参数

public class ThreadPoolExecutor extends AbstractExecutorService{}

其中最重要的构造器有

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue)
 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) 

int corePoolSize:核心池的线程大小。
int maximumPoolSize:最大容许的线程大小。
long keepAliveTime:只有正在运行的线程数量大于corePoolSize,这个参数才生效,如果一个线程无事可做,并且线程数量大于或者等于corePoolSize,超过keepAliveTime会关闭此进程,收缩到corePoolSize大小。
TimeUnit unit:时间单位。
BlockingQueue<Runnable> workQueue :缓冲队列。一般可以用ArrayBlockingQueue或者LinkedBlockingQueue。
RejectedExecutionHandler handler:饱和策略。

其中几个最重要的方法
submit()
execute()
shutDown()
shutDownNow()

43 线程池的饱和策略

线程池接受任务的过程如下:
1 提交一个任务,如果当前线程池中的数量小于corePoolSize,则创建线程运行此任务。
2 提交一个任务,如果当前线程数量大于或者等于corePoolSize,任务队列未满,则将任务放进缓冲队列。
3 提交一个任务,如果当前线程数量大于或者等于corePoolSize并且小于maximumPoolSize,任务队列已满,则创建线程运行。
4 如果当前线程数量大于或者等于maximumPoolSize,缓冲队列已满。则达到饱和状态,会根据响应的饱和状态的则略来处理。默认策略是AbortPolicy。

可以通过ThreadPoolExecutor.setRejectedExecutionHandler(RejectedExecutionHandler) 设置
策略有4种:
AbortPolicy:是默认的策略,在饱和状态下接受任务会抛出异常,程序员可以捕获异常来进行自己想要的处理。
CallerRunsPolicy:会将任务交给提交任务的线程来运行。
DiscardPolicy:直接将任务丢弃。
DiscardOldestPolicy:将workQueue头部的任务取消掉,常事重新运行。

44 类加载器和双亲委派模型

类加载气有以下几种:

1	BootstrapClassLoader(启动加载器),比如负责jre/lib/* 下面的所有包,是虚拟机自带的,底层C++实现。
2	ExtensionClassLoader(扩展类加载器),加载jre/lib/ext/*下面的所有包。
3 ApplicationClassLoader(应用程序类加载器),加载classPath(类路径下面的jar包)。可以用System.getSystemClassLoader()来获取这个加载器。
4	当然也可以定义自己的加载器。

从上至下,上面的加载器是下面加载器的父加载器,这里并不是继承的关系。双亲委派模型就体现在这里:
当一个加载器收到一个类加载的请求后,会先交给父加载器去加载,如果不在父类不能加载,自己再去加载这个类。好处是类随着这种加载机制获得了一中带有优先级的层次关系。比如Object类,是在rt.jar中,这种机制会保证这个类都被引导类加载器加载,保证了Object的唯一性。

45 CMS的几个步骤

初始标记,并发标记,重新标记,并发清除,并发重设状态。其中初始标记,重新标记需要Stop the world。

46 策略模式及其UML图

策略模式主要是对方法进行包装,将不同的方法封装在实现了同一个接口的类中。有环境角色,策略抽象角色,策略具体角色。

这里写图片描述


47 常用的LINUX命令

查看文件命令:cat head tail more less vim vi gvim
查找命令:grep,find,locate,whereis,which

用户管理命令:

	groupadd user,
	groupdel user,
	查看当前用户所在组(groups someuser),
	将用户组test修改为testnew(groupmod -n testnew test)
将用户test添加到test2用户组并将用户目录设置为~/test

usermod -d ~/test -G test2 test

gpasswd -a test test2
将用户test从test2中删除
	
gpasswd -d test test2

系统性能维护命令:
top


48 排序算法

交换排序:
冒泡排序:点击我查看
快速排序:点击我查看

插入排序:
直接插入排序:点击我查看
希尔排序:点击我查看

选择排序和堆排序:点击我查看

本文所有代码均在Github上共享:查看Github
更多资源
请点击我
还有我

49 有关数据库

有待更新

50 阻塞队列

1 非阻塞队列

我们一般会接触到非阻塞队列  PriorityQueue,LinkedList(LinkedList实现了Deque)。但是当涉及到多线程操作的时候(比如生产者和消费者模式),就会显得很不方便。所以这里就会用到阻塞队列。

2 阻塞队列的种类:

  • (1)ArrayBlockingQueue:基于数组的一个阻塞队列,比较常用 的阻塞队列。有界的阻塞队列,实例化的 时候一定要指定容量参数,还可以指定公平性,和初始化会用到的集合。当然是容量参数是一定得有的。元素是FIFO进队和出队。
  • (2)LinkedBlockingQueue:基于链表的阻塞队列,如果没有指定容量参数,默认的容量大小为 Integer.MAX_VALUE。元素是FIFO进队和出队。
  • (3)PriorityBlockingQueue:无界的阻塞队列(向其插入元素的时候不会失败),但是它不是FIFO的顺序进队和出队。它是通过元素的优先级来排序的,优先级高的元素会优先出队。
  • (4)DelayQueue(基于PriorityQueue):延迟阻塞队列。其中的元素只有在延迟了一定的时间后才能够出队列。

3 常用到的方法

非阻塞队列常用的方法有(非阻塞队列中的方法都没有进行线程同步):

add(E e):向队尾添加元素,添加失败(队满)抛出异常。

remove():从队首移除元素,如果移除失败会抛出异常。

off(E e):向队尾添加元素,添加成功返回true,失败返回false。

poll():从队首获取并且移除元素,如果成功返回队首元素,如果移除失败,则返回null;
通常用后2中方法,因为可以根据返回值判断操作是否成功。

阻塞队列常用到方法:

阻塞队列除了有以上非阻塞队列的方法外(将以上的方法进行了同步)。还添加了以下方法:

take():从队首获取元素,成功返回队首的值,失败(队列空)则阻塞等待。

put(E e):向队尾添加元素,添加失败阻塞等待。

offer(E e,Time t,TimeUnit unit):向队尾添加元素,如果等待一段时间后添加仍然失败则返回false。

poll():从队首获取元素,如果等待一段时间后获取元素仍然失败则返回null。

本文出自
代码大湿
代码大湿

posted on 2016-08-17 18:43  生活旅者  阅读(925)  评论(2编辑  收藏  举报