岗位:百度ACG物联网部门后端开发Java日常实习
面试轮次:技术面一面
NIO模型和BIO模型
BIO(blocking I/O),同步阻塞式I/O,即客户端与服务器建立一个连接时,服务器就会启动一个线程去进行处理,如果该连接上没有I/O请求,则负责处理该连接的线程就会发生阻塞。
NIO(no-blocking I/O),同步非阻塞式I/O,即当客户端与服务器建立一个连接后,会将该连接注册到多路复用器(selector)上,用一个线程对这些连接进行轮询,如果连接上有I/O请求,再启动一个线程去对其进行处理。
AIO(asynchronized I/O),异步I/O,不用进行轮询,当I/O完成之后再通知系统启动一个线程进行处理。
NIO相较于BIO的优势
NIO相较于BIO减少了线程个数,减少了创建线程的开销,减少了线程阻塞,减少了系统的上下文切换的开销。
Java如何实现NIO
Java对于NIO模型的实现有三个核心类:分别是Buffer、Channel、Selector,Buffer是作为数据的缓冲区,数据的读取和写入都是写入缓冲区中,Channel是数据的传输通道,负责往缓冲区中写入数据或者从缓冲区中获取数据,Selector是多路复用器,负责监听是否有读操作,并将ByteBuffer读入Channel之中。
Netty如何解析HTTP请求
HttpServerCodec类和HttpObjectAggregator类合作将 HttpMessage(请求行、请求头) 和 HttpConent(请求体)整合为FullHttpRequest或者FullHttpResponse。
Netty如何维护长连接模式
Netty中可使用ChannelOption.SO_KEEPALIVE开启心跳机制,利用IdleStateHandler类设置读超时或者写超时,利用自定义心跳机制的方式维护长连接。
class test extends Thread{ static final Object lock1=new Object(); static final Object lock2=new Object(); boolean flag; test(boolean flag){ this.flag=flag; } @Override public void run(){ if(flag){ synchronized (lock1){ System.out.println("I got lock1......."); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lock2){ System.out.println("I got lock2......."); } } }else{ synchronized (lock2){ System.out.println("I got lock2......."); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lock1){ System.out.println("I got lock1......."); } } } } public static void main(String[] args) { test t1=new test(true); test t2=new test(false); t1.start(); t2.start(); } }
如何实现一个比vector更加高效的线程安全容器
(1)vector是方法加锁,可以使用代码块加锁来替换方法加锁
(2)数组分段加锁
(3)synchronized关键字是悲观锁,可以使用CAS乐观锁替换悲观锁
JVM是如何加载class文件的
JVM是通过类加载器去加载.class文件的,同时JVM中也存在多个类加载器:启动类加载器、标准扩展类加载器、系统类加载器、自定义类加载器,而且根据双亲委派机制,当需要加载一个类是,类加载器的加载顺序是:启动类加载器 -> 标准扩展类加载器 -> 系统类加载器 ->自定义类加载器,只有当前类加载器无法加载时,才会委派给下一级的加载器进行加载,如果所有加载器都无法加载,则抛出异常ClassNotFound。
同时需要注意的是,JVM是通过全类名去加载类对象的。
为什么需要双亲委派机制
双亲委派可以防止同一个class被重复加载,同时保证核心class文件不会被篡改
柱状图的最大矩形面积