Fork me on GitHub

面试(one) 某一次一面


Spring的ioc和aop是怎么实现的?

IOC(Inverse Of Control)控制反转

也同DI(Dependency Injection)依赖注入。
将对在自身对象中的一个内置对象的控制反转,反转后不再由自己本身的对象进行控制这个内置对象的创建,而是由第三方系统去控制这个内置对象的创建。
实现:
(1)将bean之间的依赖关系尽可能地抓换为关联关系;
(2)将对具体类的关联尽可能地转换为对Java interface的关联,而不是与具体的服务对象相关联;
(3)Bean实例具体关联相关java interface的哪个实现类的实例,在配置信息的元数据中描述;
(4)由IoC组件(或称容器)根据配置信息,实例化具体bean类、将bean之间的依赖关系注入进来。

AOP(Aspect Oriented Programming)面向切面编程。

当前已经成为一种比较成熟的编程思想,可以用来很好的解决应用系统中分布于各个模块的交叉关注点问题。在轻量级的J2EE中应用开发中,使用AOP来灵活处理一些具有横切性质的系统级服务,如事务处理、安全检查、缓存、对象池管理等,已经成为一种非常适用的解决方案。 AOP中比较重要的概念有:Aspect、JoinPoint、PonitCut、Advice、Introduction、Weave、Target Object、Proxy Object等。

tcp的三次握手?

首先由Client发出请求连接即 SYN=1 ACK=0,TCP规定SYN=1时不能携带数据,但要消耗一个序号,因此声明自己的序号是 seq=x。然后 Server 进行回复确认,即 SYN=1 ACK=1 seq=y,ack=x+1。再然后 Client 再进行一次确认,但不用SYN 了,这时即为 ACK=1, seq=x+1,ack=y+1。

tcp的状态?

tcp的11种状态:

  1. CLOSED:初始状态,表示TCP连接是“关闭着的”或“未打开的”。
  2. LISTEN :表示服务器端的某个SOCKET处于监听状态,可以接受客户端的连接。
  3. SYN_RCVD :表示服务器接收到了来自客户端请求连接的SYN报文。在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,基本上用netstat很难看到这种状态,除非故意写一个监测程序,将三次TCP握手过程中最后一个ACK报文不予发送。当TCP连接处于此状态时,再收到客户端的ACK报文,它就会进入到ESTABLISHED 状态。
  4. SYN_SENT :这个状态与SYN_RCVD 状态相呼应,当客户端SOCKET执行connect()进行连接时,它首先发送SYN报文,然后随即进入到SYN_SENT 状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT 状态表示客户端已发送SYN报文。
  5. ESTABLISHED :表示TCP连接已经成功建立。
  6. FIN_WAIT_1 :这个状态得好好解释一下,其实FIN_WAIT_1 和FIN_WAIT_2 两种状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET进入到FIN_WAIT_1 状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2 状态。当然在实际的正常情况下,无论对方处于任何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1 状态一般是比较难见到的,而FIN_WAIT_2 状态有时仍可以用netstat看到。
  7. FIN_WAIT_2 :上面已经解释了这种状态的由来,实际上FIN_WAIT_2状态下的SOCKET表示半连接,即有一方调用close()主动要求关闭连接。注意:FIN_WAIT_2 是没有超时的(不像TIME_WAIT 状态),这种状态下如果对方不关闭(不配合完成4次挥手过程),那这个 FIN_WAIT_2 状态将一直保持到系统重启,越来越多的FIN_WAIT_2 状态会导致内核crash。
  8. TIME_WAIT :表示收到了对方的FIN报文,并发送出了ACK报文。 TIME_WAIT状态下的TCP连接会等待2*MSL(Max Segment Lifetime,最大分段生存期,指一个TCP报文在Internet上的最长生存时间。每个具体的TCP协议实现都必须选择一个确定的MSL值,RFC 1122建议是2分钟,但BSD传统实现采用了30秒,Linux可以cat /proc/sys/net/ipv4/tcp_fin_timeout看到本机的这个值),然后即可回到CLOSED 可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。(这种情况应该就是四次挥手变成三次挥手的那种情况)
  9. CLOSING :这种状态在实际情况中应该很少见,属于一种比较罕见的例外状态。正常情况下,当一方发送FIN报文后,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是CLOSING 状态表示一方发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什么情况下会出现此种情况呢?那就是当双方几乎在同时close()一个SOCKET的话,就出现了双方同时发送FIN报文的情况,这是就会出现CLOSING 状态,表示双方都正在关闭SOCKET连接。
  10. CLOSE_WAIT :表示正在等待关闭。怎么理解呢?当对方close()一个SOCKET后发送FIN报文给自己,系统毫无疑问地将会回应一个ACK报文给对方,此时TCP连接则进入到CLOSE_WAIT状态。接下来呢,需要检查自己是否还有数据要发送给对方,如果没有的话,也就可以close()这个SOCKET并发送FIN报文给对方,即关闭自己到对方这个方向的连接。有数据的话则看程序的策略,继续发送或丢弃。简单地说,当处于CLOSE_WAIT 状态下,需要完成的事情是等待你去关闭连接。
  11. LAST_ACK :当被动关闭的一方在发送FIN报文后,等待对方的ACK报文的时候,就处于LAST_ACK 状态。当收到对方的ACK报文后,也就可以进入到CLOSED 可用状态了。

servlet中的get和post方法有哪些区别?

  1. GET中的总字符数是有限的。
  2. GET发送的数据会追加到URL的后面。
  3. GET请求可以建立书签。
  4. GET请求是幂等的,不会修改服务器上的任何内容,能执行多次而不会产生不好的副作用。
  5. POST不是幂等的,POST提交的数据可能用于不可逆转的事务。
  6. POST发送的数据是可以很大的,理论不受限,例如可以传文件。
  7. POST将表单内的数据放置在HTML HEADER内一起传送所指的URL地址。是对用户透明的。
  8. GET安全性非常低,POST安全性较高。但是执行效率却比POST方法好。

什么是高并发?

高并发(High Concurrency)是互联网分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计保证系统能够同时并行处理很多请求。高并发相关常用的一些指标有响应时间(Response Time),吞吐量(Throughput),每秒查询率QPS(Query Per Second),并发用户数等。

什么是线程?

有时被称为轻量进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位。

线程有哪些状态?

  1. 创建状态。在生成线程对象,并没有调用该对象的start方法,这是线程处于创建状态。
  2. 就绪状态。当调用了线程对象的start方法之后,该线程就进入了就绪状态,但是此时线程调度程序还没有把该线程设置为当前线程,此时处于就绪状态。在线程运行之后,从等待或者睡眠中回来之后,也会处于就绪状态。
  3. 运行状态。线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始运行run函数当中的代码。
  4. 阻塞状态。线程正在运行的时候,被暂停,通常是为了等待某个事件的发生(比如说某项资源就绪)之后再继续运行。sleep,suspend,wait等方法都可以导致线程阻塞。
  5. 死亡状态。如果一个线程的run方法执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪。

什么情况下用到多线程?

  1. 程序包含复杂的计算任务时
    主要是利用多线程获取更多的CPU时间(资源)。

  2. 处理速度较慢的外围设备
    比如:打印时。再比如网络程序,涉及数据包的收发,时间因素不定。使用独立的线程处理这些任务,可使程序无需专门等待结果。

  3. 程序设计自身的需要
    WINDOWS系统是基于消息循环的抢占式多任务系统,为使消息循环系统不至于阻塞,程序需要多个线程的来共同完成某些任务。

有哪些锁?

锁分类:

  1. 公平锁/非公平锁
  2. 可重入锁
  3. 独享锁/共享锁
  4. 互斥锁/读写锁
  5. 乐观锁/悲观锁
  6. 分段锁
  7. 偏向锁/轻量级锁/重量级锁
  8. 自旋锁

ReentrantLock和synchronized的区别?

  1. synchronized是托管给JVM执行的,而Lock是Java写的控制锁的代码。
  2. synchronized原始采用的是CPU悲观锁机制,即线程获得的是独占锁。独占锁意味着其他线程只能依靠阻塞来等待线程释放锁。而在CPU转换线程阻塞时会引起线程上下文切换,当有很多线程竞争锁的时候,会引起CPU频繁的上下文切换导致效率很低。 
  3. Lock用的是乐观锁方式。每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。
  4. ReentrantLock必须在finally中释放锁,否则后果很严重,编码角度来说使用synchronized更加简单,不容易遗漏或者出错。
  5. ReentrantLock提供了可轮询的锁请求,他可以尝试的去取得锁,如果取得成功则继续处理,取得不成功,可以等下次运行的时候处理,所以不容易产生死锁,而synchronized则一旦进入锁请求要么成功,要么一直阻塞,所以更容易产生死锁。
  6. synchronized的话,锁的范围是整个方法或synchronized块部分;而Lock因为是方法调用,可以跨方法,灵活性更大。

什么是悲观锁和乐观锁?

悲观锁:

总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。再比如Java里面的同步原语synchronized关键字的实现也是悲观锁。

乐观锁:

顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。

java中哪些容器是线程安全的,例如vector?

同步容器类:使用了synchronized

  1. Vector
  2. HashTable
    并发容器:
  3. ConcurrentHashMap:分段
  4. CopyOnWriteArrayList:写时复制
  5. CopyOnWriteArraySet:写时复制

    Queue:

  6. ConcurrentLinkedQueue:是使用非阻塞的方式实现的基于链接节点的无界的线程安全队列,性能非常好。
    (java.util.concurrent.BlockingQueue 接口代表了线程安全的队列。)
  7. ArrayBlockingQueue:基于数组的有界阻塞队列
  8. LinkedBlockingQueue:基于链表的有界阻塞队列。
  9. PriorityBlockingQueue:支持优先级的无界阻塞队列,即该阻塞队列中的元素可自动排序。默认情况下,元素采取自然升序排列
  10. DelayQueue:一种延时获取元素的无界阻塞队列。
  11. SynchronousQueue:不存储元素的阻塞队列。每个put操作必须等待一个take操作,否则不能继续添加元素。内部其实没有任何一个元素,容量是0

    Deque:

    (Deque接口定义了双向队列。双向队列允许在队列头和尾部进行入队出队操作。)
  12. ArrayDeque:基于数组的双向非阻塞队列。
  13. LinkedBlockingDeque:基于链表的双向阻塞队列。

    Sorted容器:

  14. ConcurrentSkipListMap:是TreeMap的线程安全版本
  15. ConcurrentSkipListSet:是TreeSet的线程安全版本

oracle的分页举例?

1
2
3
SELECT * FROM 
( SELECT ROWNUM r, t1.* FROM student t1 WHERE ROWNUM < 20 ) t2
where t2.r >= 15;

数据库有哪些优化方式?

  1. 索引
  2. 分库分表分区
  3. 数据库引擎
  4. 预处理
  5. mysql like查询
  6. 读写分离

什么是数据库的脏读,怎么防止脏读?

脏读就是指读到还没完全弄好的数据。比如,你要读取数据库中的字段A、字段B,你读取时恰巧有其他用户正在更新这2个字段,而且是先更新A、再更新B,此时就可能会发生脏读:

  1. 如果都未更新你就读取了,或者都更新完了你才读取,这都不是脏读,因为你得到的是更新前的有效值,或完全更新后的值。
  2. 如果那个用户更新一半你就读取了,也就是说更新了A,正打算要更新B但尚未更新时,你就读取了,此时你得到的就是脏数据。

避免脏读的办法就是采取事务,使得他用户正在更新时锁定数据库,阻止你读取,直至全部完成才让你读取。

springboot运行是执行哪个文件就行了?

运行的是【工程名字+Application.java】这个文件。

java使用哪个命令运行jar包?

  1. java -cp
    java -cp 和 -classpath 一样,是指定类运行所依赖其他类的路径,通常是类库,jar包之类,需要全路径到jar包,
    window上分号“;”
    linux上分号“:”
    java -cp .;myClass.jar packname.mainclassname
    表达式支持通配符,例如:
    java -cp .;c:\classes01\myClass.jar;c:\classes02*.jar packname.mainclassname
    java -cp lib/;etc/ com.Start param1 param2
    将lib下的所有jar文件以及etc下的所有配置文件添加到 classpath 中
    并在classpath 中寻找 com.Start类(main方法类)并运行
    param1,param2 为main方法的参数可不填
    注意:jar 文件引入classpath,通配符不能写成
    .jar, 只能使用 或 123
    注意:配置文件引入classpath,只能写到目录 /, 不能添加 *
  2. java -jar
    java -jar myClass.jar
    执行该命令时,会用到目录META-INF\MANIFEST.MF文件,
    在该文件中,有一个叫Main-Class的参数,它说明了java -jar命令执行的类
    java -jar *.jar param1 param2
    运行jar包,会自动到 jar 包中查询mainfest中定义的启动类并运行
    param1,param2 为main方法的参数可不填

linux上查询进程服务的命令?

ps aux

linux上程序运行cpu过高,使用哪个命令定位到导致其的代码位置?

jstack是java虚拟机自带的一种堆栈跟踪工具。jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项”-J-d64”,Windows的jstack使用方式只支持以下的这种方式:
jstack [-l] pid
主要分为两个功能:

  1. 针对活着的进程做本地的或远程的线程dump;
  2. 针对core文件做线程dump。
    jstack用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。 线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。 如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。
-------------本文结束感谢您的阅读-------------
如果您对博主的原创满意,欢迎您继续支持下博主~