String,StringBuffer,SrtingBuilder的区别
目录
- java异常
java异常
异常处理机制主要回答了三个问题
- what:异常类型回答了什么被抛出
- where:异常堆栈跟踪回答了在哪抛出
- why:异常信息回答了为什么抛出
Java的异常体系
RuntimeException:不可预知的,程序应当自行避免
- NullpointException——空指针异常
- ClassCastException——类型强制转换异常
- IllegalArragumentException——传递非法参数异常
- IndexOutOfBoundsException——下标越界异常
- NumberFormatException——数字格式异常
非RuntimeException:可预知的,从编译器校验的异常
- ClassNotFoundException——找不到指定的class的异常
- IOException——IO操作异常
Error
- NoClassDefFoundError——找不到class定义的异常
- StackOverflowError——深递归导致栈被耗尽而抛出的异常
- OutOfMemoryError——内存溢出异常
NoClassDefFoundError的成因:
- 类依赖的class或者jar不存在
- 类文件存在,但是存在不同的域中
- 大小写问题,javac编译的时候是无视大小写的,很有可能编译出来的class文件就与想要的不一样
从责任角度看:
- Error属于JVM需要负担的责任
- RuntimeException是程序应该承担的责任
- Check Exception可检查异常是Java编译器应该负担的责任
Error和Exception的区别
从概念角度解析Java的异常处理机制
- Error:程序无法处理的系统错误,编译器不检查
- Exception:程序可以处理的异常,捕获后可能恢复
- 总结:前者是程序无法处理的错误,后者是可以处理的异常
Java的异常处理机制
抛出异常:创建异常对象,交由运行时系统处理
在用户看来,应用系统发生的所有异常都是应用系统内部的异常
- 设计一个通用的继承自RuntimeException的异常来同一处理
- 其余异常都统一译为上述异常AppException
- 在catch之后,抛出上述异常的子类,并提供足以定位的信息
Java异常处理消耗性能的地方
- try-catch块印象概念股JVM的优化
- 异常对象实例需要保存栈快照等信息,开销较大
Java集合框架
工作中消失而面试却长存的算法与数据结构
- 优秀的算法和数据结构被封装到了Java的集合框架
数据结构考点
- 数组和链表的区别
- 链表的操作,如反转,链表环路检测,双向链表,循环链表相关操作
- 队列,栈的应用
- 二叉树的遍历方式及其递归和非递归的实现
- 红黑树的旋转
算法考点
- 内部排序:如递归排序、交换排序(冒泡、快排)、选择排序、插入排序
- 外部排序:应掌握如何利用有限的内存配合海量的外部存储来处理超大的数据集,写不出也要有相关的思路
HashMap、HashTable、ConccurentHashMap
HashMap(Java8以前):数组+链表
hash(key.hashCode())%len
HashMap(Java8及以后):数组+链表+红黑树
性能从O(n)提高到O(logn)
如何优化Hashtable?
- 通过锁细粒度化,将整锁拆解多个锁进行优化
早期的ConcurrentHashMap:通过分段锁Segment来实现
数据+链表
ConcurrentHashMap
当前的ConcurrentHashMap:CAS+synchronized使锁更细化
数组+链表+红黑树
ConcurrentHashMap:put方法的逻辑
- 判断Node[]数组是否初始化,没有则进行初始化操作
- 通过hash定位数组的索引坐标,是否有Node节点,如果没有则使用CAS进行添加(链表的头结点),添加失败则进入下次循环
- 检查到内部正在扩容,就帮助它一块扩容
- 如果f!=null,则使用synchronized锁住f元素(链表/红黑二叉树的头元素)
- 如果是Node(链表结构)则执行链表ode添加操作
- 如果是TreeNode(树形结构)则执行树添加操作
- 判断链表长度已经达到临界值,当然这个8是默认值,大家也可以去做调整,当节点数超过这个值就需要把链表转换为树结构
ConcurrentHashMap总结:比起Segment,锁拆的更细
- 首先使用无锁操作CAS插入头结点,失败则循环重试
- 若头结点已存在,则尝试获取头结点的同步锁,再进行操作
ConcurrentHashMap:注意
- size()和mappingCount()的一桶,两者计算是否准确
- 多线程环境下如何进行扩容
三者的区别
- HashMap线程不安全,数组+链表+红黑树
- Hashtable线程安全,锁住整个对象,数组+链表
- ConcurrentHashMap线程安全,CAS+同步锁,数组+链表+红黑树
- HashMap的key、value均可为null,而其他的两个类不支持
Java.util.concurrent:提供了并发编程的解决方案
- CAS是java.util.concurrent.atomic包的基础
- AQS是java.util.concurrent.locks包以及一些常用类比如Semophore,ReentrantLock等类的基础
J.U.C包的分类
- 线程执行器executor
- 锁locks
- 原子变量类atomic
- 并发工具类tools
- 并发集合collections
CountDownLatch:让主线程等待一组时间后继续执行
- 事件指的是CountDownLatch里的countDown()
CyclicBarrier:阻塞当前线程,等待其他线程
- 等待其他线程,且会阻塞自己当前线程,所有线程必须同时到达栅栏位置后,才能继续执行
- 所有线程到达栅栏处,可以触发执行另一个预先设置的线程
Semaphore:控制某个资源可被同时访问的线程个数
BlockingQueue:提供可阻塞的入队和出队操作
主要用于生产者-消费者模式,在多线程场景时生产者线程在队列尾部添加元素,而消费者线程则在队列头部消费元素,通过这种方式能够到达将任务的生产和消费进行隔离的目的
- ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列
- LinkedBlockingQueue:一个由链表结构组成的有界/无界阻塞队列
- PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列
- DealyQueue:一个使用优先级队列实现的无界阻塞队列
- SynchronousQueue:一个不存储元素的阻塞队列
- LinkedTransferQueue:一个由链表结构哦组成的无界阻塞队列
- LinkedBlockingQueue:一个由链表结构组成的双向阻塞队列
Java的IO机制
BIO、NIO、AIO
Block-IO:InputStream和OutputStream,Reader和Writer
NonBlock-IO:构建多路复用的、同步非阻塞的IO操作
NIO的核心
- Channels
- FileChannel
- transferTo:把FileChannel中的数据拷贝到另一个Channel
- transferFrom:把另一个Channel中的数据拷贝到FileChannel避免了两次用户态巨额内核态间的上下文切换,即“零拷贝”,效率较高
- DatagramChannel
- SocketChannel
- ServerSocketChannel
- FileChannel
- Buufers
- ByteBuffer
- CharBuffer
- DoubleBuffer
- FloatBuffer
- IntBuffer
- LongBuffer
- ShortBuffer
- MappedByteBuffer
- Seletors
select、poll、epoll的区别
支持一个进程所能打开的最大连接数
FD剧增后带来的IO效率问题
Asynchronus IO:基于时间和回到机制
AIO如何进一步加工处理结果
- 基于回调:实现ComplerionHandlerj接口,调用时触发回调函数
- 返回Future:通过isDone()查看是否准备好,通过get()等待返回数据