面试总结6——杂七杂八总结

此部分为面试过程中遇到或者其他人的面经中看到的,也整理了下来,杂七杂八没有分类

socket编程

  1. 应用层与TCP/IP协议族通信的中间软件抽象层,表现为一个封装了TCP/IP协议族的编程接口。
  2. 应用程序可以通过它发送或接收数据,可对其像对文件一样的打开、读写和关闭。
  3. 应用程序利用套接字与网络中的其他应用程序进行通信。
  4. Tcp连接的端点,是ip地址:端口号的组合。

定义:

套接字使用TCP提供了两台计算机之间的通信机制。

服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。

在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

java中的锁池和等待池

Java平台中,因为有内置锁的机制,每个对象都可以承担锁的功能。Java虚拟机会为每个对象维护两“集合”:一个叫Entry Set(入口集),另外一个叫Wait Set(等待集)。

  1. EntrySet(锁池):存储等待获取objectX这个锁的所有线程。
  2. WaitSet(等待池):存储执行了objectX.wait()/wait(long)的线程。

 

锁池:

因申请锁而落选的线程就会被存入objectX对应的锁池之中,当objectX被其持有线程(这里就是B)释放时,锁池中的一个任意(注意是“任意”,而不一定是锁池中等待时间最长或者最短的)线程会被唤醒(即线程的生命周期状态变更为RUNNABLE)。这个被唤醒的线程会与其他活跃线程(即不处于锁池之中,且线程的生命周期状态为RUNNABLE的线程)再次抢占objectX。这时,被唤醒的线程如果成功申请到objectX,那么该线程就从锁池中移除。否则,被唤醒的线程仍然会停留在锁池中,并再次被暂停,以等待下次申请锁的机会。

等待池:

如果有个线程执行了objectX.wait(),那么该线程就会被暂停(线程的生命周期状态会被调整为Waiting),并且会释放掉objectX锁(因为wait()方法必须出现在synchronized中,所以在执行wait()方法之前线程A肯定拥有了该对象的锁),然后被存入objectX的等待池之中。此时,该线程就被称为objectX的等待线程。当其他线程执行了objectX.notify()/notifyAll()时,等待池中的一个(或者多个,取决于被调用的是notify还是notifyAll方法)任意(注意是“任意”,而不一定是等待池中等待时间最长或者最短的)等待线程会被唤醒,这些被唤醒的线程会被放到锁池中,会与锁池中已经存在的线程以及其他(可能的)活跃线程共同参与抢夺objectX。

解决hash冲突的方法

1,开放地址法

线性探测:冲突发生时,顺序查看表中下一单元,直到找出一个空单元或查遍全表。

二次探测:冲突发生时,在表的左右进行跳跃式探测,比较灵活。

伪随机探测:建立一个伪随机序列,hash+随机值,若还冲突则选择下一个随机值。

2,链地址法:建立单链表。

3,再哈希法:构造多个不同的哈希函数,产生冲突则选择下一个哈希函数。

4,建立公共溢出区:将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表。

拉链法优点:简单,且无堆积现象;适合于造表前无法确定表长的情况;删除结点的操作易于实现;指针需要额外的空间。

开放地址法:当结点规模较大时会浪费很多空间;删除结点不能简单地将被删结点的空间置为空,否则将截断在它之后填人散列表的同义词结点的查找路径,只能在被删结点上做删除标记;

数据存储的大小端

在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于 8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。

大端模式:是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。

小端模式:是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。

堆、栈的生长方向

栈是由上往下生长的(高位->低位),堆相反,由下往上生长(低位->高位)。

内存泄露

定义:可达,无用

当一个对象已经不需要再使用本该被回收时,另外一个正在使用的对象持有它的引用从而导致它不能被回收,这导致本该被回收的对象不能被回收而停留在堆内存中,这就产生了内存泄漏。

影响:

内存泄漏是造成应用程序OOM的主要原因之一。

如何检查和分析内存泄漏?

Jconsole:监控CPU、内存、线程等状况。

JvisualVM:包括 jmx 监控、dump文件分析等功能

可能存在内存泄漏的情况:

  1. 静态static特性:静态特性使得对象生命周期和应用的生命周期一样长,如果一个对象不再使用了,但是具有静态属性的对象还持有该对象的引用,就会使得该对象不能被正常回收,从而导致了内存泄漏。比如:静态集合类:hashmap,linkedlist,则容器中的对象在程序结束之前将不能被释放。单例对象也是静态的,单例对象持有其他对象的引用。
  2. 各种连接:如数据库连接、网络连接和IO连接等。在对数据库进行操作的过程中,首先需要建立与数据库的连接,当不再使用时,需要调用close方法来释放与数据库的连接。只有连接被关闭后,垃圾回收器才会回收对应的对象。
  3. 变量不合理的作用域:一般而言,一个变量的定义的作用范围大于其使用范围,很有可能会造成内存泄漏。另一方面,如果没有及时地把对象设置为null,很有可能导致内存泄漏的发生。
  4. 内部类持有外部类:如果一个外部类的实例对象的方法返回了一个内部类的实例对象,这个内部类对象被长期引用了,即使那个外部类实例对象不再被使用,但由于内部类持有外部类的实例对象,这个外部类对象将不会被垃圾回收,这也会造成内存泄露。
  5. 改变哈希值:当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,造成内存泄露。

内存泄漏的检测和解决

如何检测:

  1. 对代码进行分析,找出内存泄漏发生的位置
  2. 使用专门的内存泄漏测试工具进行测试:MAT,LeakCanary

如何解决

  1. 集合容器的内存泄漏:退出之前,clear,然后设置为null。
  2. 使用软引用和弱引用。
  3. 尽量避免使用static,保持对对象生命周期的敏感。
  4. 各种资源使用之后及时关闭。

逃逸分析

所有的对象和数组不一定都会在堆内存分配空间

定义:

JIT的一种优化,减少内存堆分配压力。

逃逸分析,是一种可以有效减少Java 程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法。通过逃逸分析,Java Hotspot编译器能够分析出一个新的对象的引用的使用范围从而决定是否要将这个对象分配到堆上。

逃逸分析的基本行为就是分析对象动态作用域:当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参数传递到其他地方中,称为方法逃逸。

 

使用逃逸分析,编译器可以对代码做如下优化:

  1. 同步省略:如果一个对象被发现只能从一个线程被访问到,那么对于这个对象的操作可以不考虑同步。(锁消除依赖的也是逃逸分析技术)
  2. 将堆分配转化为栈分配。如果一个对象在子程序中被分配,要使指向该对象的指针永远不会逃逸,对象可能是栈分配的候选,而不是堆分配。(有些对象没有逃逸出方法,那么有可能堆内存分配会被优化成栈内存分配。这也并不是绝对的。)
  3. 分离对象或标量替换。有的对象可能不需要作为一个连续的内存结构存在也可以被访问到,那么对象的部分(或全部)可以不存储在内存,而是存储在CPU寄存器中。

 

引入背景:

Java的源代码文件变成计算机可执行的机器指令:

第一段是把.java文件转换成.class文件。

第二段编译是把.class转换成机器指令的过程。JVM 通过解释字节码将其翻译成对应的机器指令,逐条读入,逐条解释翻译。

很显然,经过解释执行,其执行速度必然会比可执行的二进制字节码程序慢很多。这就是传统的JVM的解释器(Interpreter)的功能。为了解决这种效率问题,引入了 JIT(即时编译) 技术。

引入了 JIT 技术后,Java程序还是通过解释器进行解释执行,当JVM发现某个方法或代码块运行特别频繁的时候,就会认为这是“热点代码”(Hot Spot Code)。然后JIT会把部分“热点代码”翻译成本地机器相关的机器码,并进行优化,然后再把翻译后的机器码缓存起来,以备下次使用。

序列化

1,序列化是一种处理对象流的机制——把内存中的Java对象转换成二进制流。

把对象转换为字节序列的过程称为对象的序列化

把字节序列恢复为对象的过程称为对象的反序列化

2,Java对象序列化时参与序列化的内容包含以下几个方面:

属性,包括基本数据类型、数组、其他对象的引用(深复制)。

类名。

3,应用:数据持久化(存储到磁盘,用法比较少,一般使用数据库持久化);网络传输对象(远程方法调用RMI和远程过程调用RPC)。

4,实现:被序列化的对象实现serializable接口,其中没有任何方法,只为了标记对象是可被序列化的。

5,Java的序列化机制是通过运行时判断类的序列化ID(serialVersionUID)来判定版本的一致性(内存中是否已经存在该对象)。在反序列化时,java虚拟机会通过二进制流中的serialVersionUID与本地的对应的实体类进行比较,如果相同就认为是一致的,可以进行反序列化,正确获得信息,否则抛出序列化版本不一致的异常。

6,不能被序列化的内容:static修饰的属性(JAVA序列化保存的是对象的状态,而静态变量不是对象的状态而是类的状态,所以序列化不保存静态变量),transient修饰的属性(在不希望被序列化的字段前添加transient关键字,序列化时将忽略该字段,反序列化的时候也是不可恢复;final变量直接通过值参与序列化,所以将final变量声明为transient变量不会产生任何影响),成员方法。

7,想序列化又不可以被序列化的数据字段进行写出和读入操作:标注为transient,因为Java中,对象的序列化可以通过实现两种接口来实现,若实现的是Serializable接口,则所有的序列化将会自动进行,若实现的是Externalizable接口,则没有任何东西可以自动序列化,需要在writeExternal方法中进行手工指定所要序列化的变量,这与是否被transient修饰无关。

Fail-fast(快速失败),fail-safe(安全失败)

Fail-fast:

  1. 在用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的内容进行了修改(增加、删除、修改),则会抛出Concurrent Modification Exception。
  2. 原理:迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount 变量。集合在被遍历期间如果内容发生变化,就会改变modCount的值。每当迭代器使用hashNext()/next()遍历下一个元素之前,都会检测modCount变量是否为expectedmodCount值,是的话就返回遍历;否则抛出异常,终止遍历。
  3. 注意:这里异常的抛出条件是检测到 modCount!=expectedmodCount 这个条件。如果集合发生变化时修改modCount值刚好又设置为了expectedmodCount值,则异常不会抛出。因此,不能依赖于这个异常是否抛出而进行并发操作的编程,这个异常只建议用于检测并发修改的bug。
  4. 场景:java.util包下的集合类都是快速失败的,比如hashmap,不能在多线程下发生并发修改(迭代过程中被修改)。

 

Fail-safe:

  1. 采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。
  2. 原理:由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会触发Concurrent Modification Exception。
  3. 缺点:基于拷贝内容的优点是避免了Concurrent Modification Exception,但同样地,迭代器并不能访问到修改后的内容,即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的。
  4. 场景:java.util.concurrent包下的容器都是安全失败,比如concurrentHashmap,可以在多线程下并发使用,并发修改。
  5. 缺点:复制集合,产生大量无效对象;无法保证读取的数据是目前原始数据结构中的数据。

文本文件和二进制文件的区别

计算机的存储在物理上是二进制的,所以文本文件与二进制文件的区别并不是物理上的,而是逻辑上的。这两者只是在编码层次上有差异。

文本文件是基于字符编码的文件,常见的编码有ASCII编码,UNICODE编码等等。

二进制文件是基于值编码的文件,你可以根据具体应用,指定某个值是什么意思(这样一个过程,可以看作是自定义编码。

 

记事本来说,它首先读取文件物理上所对应的二进制比特流(前面已经说了,存储都是二进制的),然后按照你所选择的解码方式来解释这个流,然后将解释结果显示出来。一般来说,你选取的解码方式会是ASCII码形式(ASCII码的一个字符是8个比特),接下来,它8个比特8个比特地来解释这个文件流。

JDBC用了哪种模式

桥接模式:抽象接口和实现类独立分开(数据库厂商和使用者)

JDK1.7和JKD1.8区别

1)1.8接口支持静态方法和默认方法(接口里面被实现的方法)

2)hashmap,concurrentMap的区别

3)移除永久代,改为元空间,

 

Jdk1.7

对集合类的语言支持

自动资源管理

Switch中使用string

Jdk1.8

Lambda表达式:允许函数作为一个方法的参数

DATE Time API:加强对日期与时间的处理。

BIO与NIO、AIO的区别详解

BIO:同步阻塞式IO,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。

NIO:同步非阻塞式IO,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。

Channel,selector,buffer,。

AIO(NIO.2):异步非阻塞式IO,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。

Statement和PreparedStatement的区别

总结:PrepareStatement:提高了可读性,安全性高(带参数?,预编译,防止sql注入),重复执行语句效率高(cache机制),灵活性(继承Statement接口)

 

详细:

1)Statement是java执行数据库操作的一个重要方法,用于在已经建立数据库连接的基础上,向数据库发送要执行的SQL语句。创建了一个对象然后去通过对象调用executeQuery方法来执行sql语句。

2)三种:

Statement:执行不带参数的简单SQL语句。数据库每次都要执行sql语句的编译,最好用于一次查询并返回结果的情形,效率高于PreparedStatement但存在sql注入风险。

PrepareStatement(从Statement继承):执行带或不带参数的预编译的SQL语句。在执行可变参数的一条sql时,PreparedStatement要比Statement效率高,安全性好,有效防止sql注入;对于多次重复执行的语句,效率也会高一点;sql语句可以带参数(?传递参数),并支持批量执行sql,采用了cache机制,预编译的语句会放在cache中,执行相同的sql语句时,可以直接从cache中取出来。

常用方法:

Boolean execute(): 在此PrepareStatement对象中执行sql语句

resultSet executeQuery():在此PrepareStatement对象中执行sql查询,并返回该查询生成的ResultSet对象

int executeUpdate():在此PrepareStatement对象中执行sql语句,语句必须是sql的DML语句(数据操作语言,如insert,update, delete),或者无返回内容的sql语句,如DDL。

CallableStatement(从PrepareStatement继承):执行对数据库已存储过程的调用。那么CallableStatement扩展了PreparedStatement的接口,用来调用存储过程,它提供了对于输入和输出参数的支持,CallableStatement 接口还有对 PreparedStatement 接口提供的输入参数的sql查询的支持。

数据库连接池是为了解决什么问题

1,java应用程序访问数据库的过程是:

装载数据库应用程序:DriverManager.registerDriver(new SQLServerDriver());

通过jdbc(Java database connection,java数据库连接)建立数据库连接:Connection conn = DriverManager.getConnection(“”);

访问数据库,执行sql语句

断开数据库连接

2,存在的问题:

每次建立连接都要讲connection加载到内存中,并且验证用户名和密码,频繁的连接操作占用系统资源和时间;

每次连接使用完需要断开,如程序出现异常而未能关闭,将会导致数据库系统内存泄露。

3,数据库连接池:负责分配、管理和释放数据库的连接。

为数据库连接建立一个缓存池,预先在缓存池中放入一定量的连接,当需要建立数据库连接时,只需要从缓存池中取出一个,使用完再放回去(队列的删除和添加操作)

可以通过连接池的管理机制监视数据库的连接的数量﹑使用情况,为系统开发﹑测试及性能调整提供依据。。

4,数据库连接池的优点:

资源重用:

更快的系统反应时间:

统一的连接管理:

5,数据库连接池的工作原理:

连接池的建立:系统初始化时,根据系统配置建立,并在池中建立几个连接对象,java提供了很多容器类,比如vector,linkedlist等。

连接池的管理:

请求连接时:是否有空闲,是否达到最大连接数,最大等待时间,抛出异常。

客户请求时,首先查看池中是否有空闲连接,如存在,分配给客户并标记该连接为正在使用,引用计数加1,若没有空间连接,则查看当前所开的连接数是否已达到最大连接数,若没有,重新创建一个分配给客户,否则按照设定的最大等待时间进行等待,若超出,抛出异常给客户。

释放连接时:判断该连接的引用次数是否超过了规定值,超过则从池中删除并判断池内总的连接数是否小于最小连接数,若小于则填满,若没有超过则将连接标记为开放状态,再次复用。

连接池的关闭:

         应用程序退出时,关闭连接池中的所有连接,释放连接池中相关资源。

6,连接池的并发问题:

加synchronized关键字。

数据库中删除的区别:

  1. truncate:删除表中全部内容,不删除定义,释放空间。
  2. delete:记录一条一条的删除,不删除定义,不释放空间。
  3. drop:删除表,删除定义,释放空间。

逻辑地址转换为物理地址

页号+页内地址

段号+段内偏移量(判断是否越界)

类加载顺序

父类静态代码块(包括静态初始化块,静态属性,但不包括静态方法)

子类静态代码块(包括静态初始化块,静态属性,但不包括静态方法 )

父类非静态代码块( 包括非静态初始化块,非静态属性 )

父类构造方法

子类非静态代码块 ( 包括非静态初始化块,非静态属性 )

子类构造方法

索引的最左匹配原则

组合索引,最左优先,

Abc建立索引,相当于建立了a,ab,abc三个索引。

Linux

  1. top:相当于任务管理器,显示当前系统中占用资源最多的一些进程,cpu、磁盘和内存使用,q退出

之后按1:显示多个cpu使用率

  1. sed 利用脚本处理文本文件
  2. shell脚本中判断上一个命令是否执行成功:$?,0表示成功,其他表示失败
  3. ps 查看当前正在运行的进程,kill用于终止进程
  4. ps-T开启线程查看,或者top-H
  5. r:读,4;w:写,2;x:执行,1;777:当前文件拥有者,同组用户,其他用户可读写执行,
  6. 查看文件权限:ls-l 或ls-ll或ls-al
  7. Pwd:输出当前工作目录
  8. Free:当前内存的使用情况,包括已用内存、可用内存和交换内存的情况
  9. Df:显示文件系统的磁盘使用情况
  10. Cp:拷贝
  11. Mv:重命名
  12. Cat:一次查看多个文件的内容
  13. chmod用于改变文件和目录的权限
  14. mkdir:创建目录
  15. ifconfig用于查看和配置Linux系统的网络接口
  16. su:切换用户账号
  17. 使用wget从网上下载软件、音乐、视频
  18. 查找命令:find(目录或文件),whereis(文件源和二进制文件),which(用于查询命令或别名的位置),locate(快速查找系统数据库中指定的内容)

 

Kill和kill-9的区别

kill和kill -9,两个命令在linux中都有杀死进程的效果,然而两命令的执行过程却大有不同

kill(默认kill-15):系统会发送一个SIGTERM信号给对应的程序。大部分程序接收到SIGTERM信号后,会先释放自己的资源,然后再停止。

kill -9:系统给对应程序发送的信号是SIGKILL,即exit。exit信号不会被系统阻塞,所以kill -9能顺利杀掉进程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值