有段时间没有更新新文章了,接下来想把文章的更新速度放慢点,主要是想写出更高质量的文章,最近收录了多年面试的经典题目,包括答案,本系列会持续更新。
- 1资源占用:进程是系统资源分配的基本单位,进程拥有自己独立的内存空间,所属同一进程的各个线程共享进程的内存空间。线程的上下文切换更快。2调度和运行:线程是进程的实体,是系统调度的基本单位,线程的调度要依赖进程,不能单独运行。
- 相同:都是实现了List接口,内部都是使用的动态数组,元素是有序的,可以根据索引来访问元素。不同:1 Vector是线程安全的,ArrayList和LinkedList是非线程安全的,所以ArrayLsit的执行的效率要高于Vector。2 Vector当需要增加长度的时候,会增加原来长度的1倍,而让ArayList会增加原来的一半。3 Vector设置了增长空间的方法,ArrayList没有设置此方法。4 LinkedList是使用的双向链表,继承了Deque接口。
这 2 者和 LinkedList 的优缺点:
很明显,LinkedList 的优点是可以实现元素的插入和删除操作。而 Vector 和 ArrayList 可以实现快速的元素的随机访问。
- 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的倍数。
- 1 String是final修饰的字符串常量,对象内容不可变。后2者都是字符串变量,内容可以改变。2 StringBuilder是非线程安全的,StringBuffer是线程安全的。所以StringBuilder的执行效率要高于StringBuffer。3 StringBuilder和StringBuffer都是继承自AbstractStringBuilder。
- 1 sleep是Thread的方法,wait是Object的方法。2 sleep会暂停线程的执行,但是不会释放锁,到了指定时间会自动释放,,而wait会释放锁,让线程进入等待锁定池。3 sleep需要捕获异常,而wait不用。4 sleep可以在任何地方使用,而wait只能在同步块或者同步方法中使用。
- 1 TCP传输数据之前需要建立连接,UDP是传送数据包,不需要建立连接。2 TCP提供可靠的传输,而且利用滑动窗口技术还提供差错检测,数据重传等服务。3 TCP是传输的二进制字节流,UDP传输数据包,而且UDP不会提供拥塞控制,当数据传输量很大的时候,并不会降低发送端的传输速率。4 TCP提供的是端到端的服务,UDP提供一对多,多对一,多对多的服务5 TCP数据包的消耗比较大,而UDP数据包消耗会很小。
类的加载顺序是:
- 加载 - >验证 - >准备 - >解析 - >初始化 - >使用 - >卸载其中前5个阶段是类的加载阶段。
加载:
- 1获取classes文件(通过类的全限定名)或者网络中的二进制字节流。2将二进制的静态存储结构转换为方法区的动态存储结构。3在堆中生成Class对象,作为对方法区的访问接口。
验证:
- 主要验证二进制文件的格式是否有错误。
准备:
- 这个阶段为类的static变量分配内存,并对其赋予默认0值,只是针对static的类变量。如果是final和static同时修饰。此时就为其分配程序中指定的值。
解析:
- 将符号引用转换为直接引用。
初始化:
- 真正意义上执行程序中的代码。为变量赋予程序中指定的值。
- 1标记 - 清理:先标记存活的对象。然后将未标记的需要清理的对象清理掉,,效率低下,会产生内存碎片。2复制算法:将堆内存划分为2部分,将存活的正在使用的对象复制到另外一个内存区域,消除了内存碎片。3标记 - 整理:标记存活的对象,然后将存活的对象向堆内存的一边移动,消除了堆内存的内存碎片。4分代回收算法:将堆内存划分为,年轻代(Eden,Survivor from,
- Survivor to),
- 年老代,永久代。然后根据不同内存区域中对象的生命周期来使用不同的回收算法。一般年轻代(因为存活对象少)使用复制算法(minor gc)。年老代使用标记 - 整理算法(major / full gc)。
Serial 收集器一般是用在 Client 的虚拟机。有年轻代和年老代。
- Serial:年轻代的垃圾回收器。使用复制算法。Serial Old:年老代的收集器,使用标记整理算法。
Parallel 收集器
- Parallel Scanvage收集器:年轻代的收集器,使用复制算法。目标是获取最大的吞吐量。Parallel Old收集器:年老代的收集器,使用标记 - 整理算法。
CMS 收集器(concurrent mark-sweep)
- 用在服务器端的收集器。目标是获得最短的用户停顿时间。
g1 收集器
- 最前沿科技的成果,但是内存布局和传统的内存布局不一样。
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 状态。
M 阶 B(B-)树有以下几点特性:
- 1如果这棵树不是空树,根节点至少有2个子节点。2中间节点至少有ceil(M / 2)个子节点。3非叶节点最多有M个子节点。4有k个关键字的节点有k + 1个子节点。5所有叶子节点都在同一层。
数据库事物有 4 个隔离级别(以下级别依次提高)
- READ UNCOMMITTED:读取未提交数据,此级别会造成脏读,不可重复读,幻读。READ COMMITTED:读取提交数据,消除了脏读,但还是会有不可重复读,幻读。大部分数据库都是这个隔离级别。oracle,sqlserver Repeatable read: 重复读,消除了脏读和不可重复读。会有幻读。Mysql是这个隔离级别。Serializable:最高隔离级别,消除了幻读。
数据库索引有聚集索引和非聚集索引。
- 聚集索引:聚集索引是表中的记录的物理顺序与索引的key的顺序相同,聚集索引是唯一索引,一个表只能有一个索引。相对于非聚集索引,聚集索引提供更快的查询速度。非聚集索引:聚集索引是表中的记录的物理顺序与索引的key的顺序不相同。不是唯一索引。
- 堆:解决程序的存储问题,存储运行时的对象,是所有线程共享的。栈:解决运行问题,存储单个线程的本地变量,运行状态,和返回结果。线程运行结束,栈也会随着消失。
JVM 运行时将内存区域分为
- 1程序计数器:是线程隔离的,只是线程下一条将要执行的指令的位置。2 JVM栈:每个线程都有自己的虚拟机栈,主要存储线程的本地变量,自然是线程隔离的。3堆:存储程序中所有的对象,是所有线程可以共享的内存区域。4方法区:存储类的信息,类变量(static变量),是所有线程共享的。
- JVM规定所有的变量都存储在主存中,而每个线程运行时都有自己的工作内存。每个线程不能自己操作主存,必须通过工作内存。一个线程不能直接访问其它线程的变量。
数据库范式有 8 个范式。通常我们设计数据库需要满足前面 3 个范式。
- 1NF数据表的字段是原子的,不可再分。2NF在1NF的基础上,非主键列对主键是完全依赖,不存在非主属性对主键的部分依赖。3NF在2NF的基础上,非主键列对主键是直接依赖,不存在非主键列对主键是传递依赖。(如非主属性C依赖于非主属性B,非主属性B依赖于主键A)
- 1原子性:一个事务对数据的操作要么成功,要么失败。如果有异常,会回滚到事务操作数据之前的状态。2一致性:事务修改数据库之前和修改数据库之后的状态要保持一致。3持久性:既事务对数据库的操作是永久性的。4隔离性:多个事务之间的操作应当是隔离的。
- 1指针碰撞法:针对连续的内存空间,有内存分配的请求的时候,将指针指向一边。2空闲表法:针对不连续的内存空间,所有的空闲内存都记录在一个表中,当需要分配内存的时候,查询这个表,将满足大小的内存分配。
- 强引用:我们平时使用到的引用都是强引用,在gc回收内存的时候。会将不可达对象回收掉。软引用:SoftReference < V > ,
- 在内存不足的时候会将软引用对象回收掉。弱引用:WeakRerence < V > ,
- gc回收的时候会将弱引用对象回收掉。虚引用:PhantomRerence < V > ,
- 此引用不能引用到对象,在跟踪gc回收器的时候使用。
- 悲观锁:数据库事务获取数据之前,将数据加锁,别的线程要读取数据会blocking。乐观锁:数据库事务获取数据不会加锁,但是更新数据的时候会检查是否有别的线程在此期间更新数据,如果有别的事务在修改数据,此事物会回滚,可以使用版本号等机制。乐观所适用于写操作很少的情况下。
- 1脏读:读取到没有提交的数据。比如老张发现自己的银行账户收进了老板打来5000元,但是老板此时还为提交事物,老发发现打钱的数来那个有误,其实是2000。老板又撤销了事物。这是后老张的银行账户其实只有2000元。2不可重复读:比如老张的老婆在用老张的账户进行取款操作,而此时老张正在使用银行卡进行pos消费。当老张老婆查询到账户还有5000,但是在老张老婆取款前,老张pos消费了3000.然后老张老婆进行取款,会显示余额不足。3幻读:老张老婆在银行部门工作,查询了老张这个月的消费账单,而然后老张又pos消费了一笔。然后老张老婆打印账单会发现多了一条记录。
Java 中是这样使用两者的:
Statement st=connectiion.createStatement();
st.execuseQuery(sql);
PreparedStatement pst=connection.preparedStatement(sql);
pst.ecxcuseQuery();
程序中应该尽量用 preparedStatement。优势如下:
- 1:可使用参数化查询。参数化查询的效率比凌乱的字符串追加的方式的效率更高。2:会有预编译处理(jdbc引擎支持的前提),会将编译好的sql语句放进数据库系统,下次可以重新使用。对于相同查询,不同参数的查询,效率会很好。3:可以防止大部分的sql注入攻击。
- 1抽象类中可以有默认的方法实现,而接口不可有有方法的实现。2抽象类的方法的修饰符可以是public,
- private,
- protected.但是接口中方法只能是public(默认就是public)3抽象类可以定义普通变量。接口中的变量只能是public static final(默认)4继承抽象类后不可以继承其他类,实现接口后可以,继承其他类。5抽象类可已有构造方法,接口不行。
使用时机:
当需要有一些方法的默认实现的时候,就用抽象类。
当还有其他的父类需要继承的时候就必须用接口。
- 1实现解耦。2用作缓冲。3异步通信,送达保证。
- 1 IO是面对字节(字符)流的,NIO是面对缓冲区的。IO面对流意味着每次从流中读取一个或者更多字节,没有被缓冲到任何其它地方,数据不能前后移动。NIO面对缓冲区更具有灵活性,它将数据读取到一个缓冲区,可以在缓冲区中前后移动数据。2 IO是阻塞模式的。NIO是非阻塞的。阻塞意味着每次读取数据的时候,一定要读取到数据,如果没有数据,此时线程不能做其它任何事情,直到等到有数据可读(数据完全写入)为止。NIO的非阻塞模式当没有数据可读的时候线程不会阻塞,会先去干其它事情,通常会去处理其它channel的读写。所以此时一个线程就可管理多个channel。
详细请
// 内部类实现
- //单例模式
- class Single {
- //将构造器变为私有
- private Single() {
- }
- //内部类
- private static class SingleHolder {
- private static final Single Instance = new Single();
- }
- public static Single getInstance() {
- return SingleHolder.Instance;
- }
- }
堆内存
- - Xms:初始内存 - Xmx:最大堆内存
非堆内存
- - XX: PermSize非堆内存初始大小 - XX: MaxPermSize:非堆内存最大大小
- 1实现变量的可见性,让读取变量的线程及时读取到变量最新的值,禁止工作线程拷贝。2防止编译器的指令重排序。
- 1 BeanFactory是最基本的接口,ApplicationContext是前者的扩展。功能更加强大。2 ApplicationContext扩展MessageSource来支持国际化功能。3 ApplicationContext有事件监听空能。因为其支持ApplicationEvent和ApplicationListener。4 ApplicationContext在容器加载的时候会初始化所有容器中的对象,BeanFactory会延迟加载,直到getBean的时候才会初始化对象。前者能更好的检查容器配置中的错误。5 BeanFactory的实现有XmlBeanFactory。ApplicationContext的实现有XmlWebApplicationContext,FileSystemXmlApplicationContext,ClassPathXmlApplicationContext,6 ApplicationContext扩展ResourceLoader(资源加载器)支持底层资源访问。
7 大原则:
- 1里氏替换原则,所有子类必须都能够代替父类。2依赖倒置原则,实现应该依赖与抽象,而不是具体3开闭原则,所有类应该对扩展开放,对修改关闭4单一职责原则,一个类应该专注与做一件事情。5迪米特原则,一个软件实体应该尽可能少得访问其它实体。6聚合原则,应该尽可能多得使用聚合或者复用,避免使用继承。7接口隔离原则,应该尽可能为客户提供单独的小的接口,而不是大的接口。
- 1使用new关键字,读取类的静态成员,设置类的静态成员值,调用类的静态方法,如果类没有被初始化,则要先初始化类。2使用java.lang.reflect中的方法进行反射调用的时候,如果类没有被初始化,则要先初始化类。3加载一个子类的时候,如果父类没有被加载,则要先加载父类。4 JVM启动的时候,要先加载主类(带有main方法的类)、5一个java.lang.invoke.MethodHandler的实例的解析结果(结果是REF_getstatic,
- REF_putstatic,
- REF_invokestatic)的方法句柄所对应的类没有被初始化,则要先初始化此类。
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>
- </link>
- </head>
详细
ConcurrentHashMap 主要有 3 个对象,HashMap,Segment,HashEntry。
ConcurrentHashMap 默认有 16 个 Segment(段),一个段里面装的是 HashMap 的一部分 Entry。操作特点:
put,get,remove 操作:都是将对应的 Segment 加锁。读写某个的 Segment 中的 Entry,并不影响其它 Segment 的操作,这是其增加 Map 性能的核心方法。
size 方法会锁定整个表。
视图就是一些 sql 语句的集合,是从数据表中提取的子集。
一般可以禁止用户访问数据库表,而以视图的方式呈现给用户,这样既可以保证数据表的安全,也可以让用户或者应用程序不受到数据库修改带来的影响。
2 者区别:
- 1视图不占用物理内存。表要占用物理内存。2视图是展现数据的窗口。表是数据内容。3我们可以对表进行修改,但是只能通过创建视图的语句来修改视图。
- 客户端第一次通过http协议访问服务器的时候,服务器会生成一些带有限制条件的key - value键值对,cookies保存在客户端,当下次同一客户端访问的时候,条件满足的时候,会将这些数据完整地带回服务器,sessions保存在服务器端。cookies保存在客户端浏览器内存中,访问服务器的时候会返回给服务器一个name叫做JSESSIONID的一个cookie。
- 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
:只有正在运行的线程数量大于 corePoolSize,这个参数才生效,如果一个线程无事可做,并且线程数量大于或者等于 corePoolSize,超过 keepAliveTime 会关闭此进程,收缩到 corePoolSize 大小。
- long keepAliveTime
:时间单位。
- TimeUnit unit
:缓冲队列。一般可以用 ArrayBlockingQueue 或者 LinkedBlockingQueue。
- BlockingQueue<Runnable> workQueue
: 饱和策略。
- RejectedExecutionHandler handler
其中几个最重要的方法
submit()
execute()
shutDown()
shutDownNow()
线程池接受任务的过程如下:
1 提交一个任务, 如果当前线程池中的数量小于 corePoolSize,则创建线程运行此任务。
2 提交一个任务,如果当前线程数量大于或者等于 corePoolSize,任务队列未满,则将任务放进缓冲队列。
3 提交一个任务,如果当前线程数量大于或者等于 corePoolSize 并且小于 maximumPoolSize,任务队列已满,则创建线程运行。
4 如果当前线程数量大于或者等于 maximumPoolSize, 缓冲队列已满。则达到饱和状态,会根据响应的饱和状态的则略来处理。默认策略是 AbortPolicy。
可以通过
设置 策略有 4 种:
- ThreadPoolExecutor.setRejectedExecutionHandler(RejectedExecutionHandler)
类加载气有以下几种:
- 1 BootstrapClassLoader(启动加载器),比如负责jre / lib
- /* 下面的所有包,是虚拟机自带的,底层C++实现。
- 2 ExtensionClassLoader(扩展类加载器),加载jre/lib/ext/*下面的所有包。
- 3 ApplicationClassLoader(应用程序类加载器),加载classPath(类路径下面的jar包)。可以用System.getSystemClassLoader()来获取这个加载器。
- 4 当然也可以定义自己的加载器。*/
从上至下,上面的加载器是下面加载器的父加载器,这里并不是继承的关系。双亲委派模型就体现在这里:
当一个加载器收到一个类加载的请求后,会先交给父加载器去加载,如果不在父类不能加载,自己再去加载这个类。好处是类随着这种加载机制获得了一中带有优先级的层次关系。比如 Object 类,是在 rt.jar 中,这种机制会保证这个类都被引导类加载器加载,保证了 Object 的唯一性。
- 初始标记,并发标记,重新标记,并发清除,并发重设状态。其中初始标记,重新标记需要Stop the world。
策略模式主要是对方法进行包装,将不同的方法封装在实现了同一个接口的类中。有环境角色,策略抽象角色,策略具体角色。
查看文件命令: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
交换排序:
冒泡排序:
快速排序:
插入排序:
直接插入排序:
希尔排序:
选择排序和堆排序:
本文所有代码均在 Github 上共享:
更多资源
1 非阻塞队列
- 我们一般会接触到非阻塞队列PriorityQueue,LinkedList(LinkedList实现了Deque)。但是当涉及到多线程操作的时候(比如生产者和消费者模式),就会显得很不方便。所以这里就会用到阻塞队列。
2 阻塞队列的种类:
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。
来源: http://www.cnblogs.com/pin-wang/p/5781172.html