200 状态码:表示请求已成功,请求所希望的响应头或数据体将随此响应返回
JVM OutOfMemonry 的种类
堆溢出(被缓存的实例对象,大的 map、list 引用大的对象等等)、栈溢出(栈帧太多,也就是函数调用层级过多时出现的异常,检查是否有死递归的情况)、方法区溢出
Java 方法区中存放哪些东西?JVM 如何控制方法区的大小以及内存溢出的原因和解决
方法区的大小不必是固定的,JVM 可以根据应用的需要动态调整。方法区主要存放常量、静态变量、虚拟机加载的类信息以及编译后的代码,运行时常量池。通过配置 PermGenspace可以控制方法区的大小
Java 中的线程有几种状态
新建状态(New):新创建了一个线程对象
就绪状态(Runnable):线程对象创建之后,其他线程调用了该对象的 start() 方法。改状态的线程位于可运行线程池中,变得可运行,等待获取 CPU 的使用权
运行状态(Running):就绪状态的线程获取了 CPU,执行程序代码
阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃 CPU 使用权,暂时停止运行。直到线程进入就绪状态。
java 中的线程池实现有哪些?FixedThreadPool 底层使用什么任务队列?
newFixedThreadPool:创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小
- 线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程
newSingleThreadPool:创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务
- 如果这个唯一的线程因为异常结束,那么会有一个新的线程来接替它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行
newCacheThreadpool:创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程数,那么会回收部分空闲(60 秒不执行)的线程
当任务数增加时,此线程又可以智能的添加新线程来处理任务。
此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程数
newScheduledThreadPool:创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求
java 中 synchronized 代码块的实现,以及 jdk1.6 对锁的优化
被 synchronized 关键字修饰的代码块在被编译成字节码的时候会在该代码块的开头和结尾分别插入 monitorenter 和 monitorexit 指令。任何对象都有一个 monitor 与之关联,当一个 monitor 被持有后,它将处于锁定状态。线程执行到 monitorenter 指令时,将会尝试获取对象所对应的 monitor 的所有权,即尝试获得对象的锁。虚拟机在执行这两个指令的时候会检查对象的锁状态是否为空或当前线程是否已经拥有该对象锁,如果是,则将对象锁的计数器加 1 直接进入同步代码执行。如果不是,当前线程就要阻塞等待,直到锁释放。也就是说 synchronized 是可重入锁。
synchronized 与 Lock 的区别的使用场景
- Lock可以使用 Condition 进行线程之间的调度
Synchronized 则使用 Object 对象本身的 notify,wait,notifyAll 调度机制
Condition 是 Java5 以后出现的机制,它有更好的灵活性,而且在一个对象里面可以有多个 condition,则线程可以注册在不同的 Condition,从而可以有选择性的调度线程,更加灵活。Synchronized 就相当于整个对象只有一个单一的 Condition 所有线程都注册在它身上,线程调度的时候之后调度所有的注册线程,没有选择权,会出现相当大的问题
ReentrantLock 的使用场景
需要使用可重入锁时,即当该线程正在运行时,可以再次进入并执行它
并发竞争很高的情况下
需要使用可中断锁
尝试等待执行:如果发现该操作已在执行,则尝试等待一段时间,等待超时则不执行
如果发现该操作已在执行中则不再执行(有状态执行),例如:用在定时任务时,如果任务执行时间可能超过下次计划执行时间,确保该有状态任务只有一个正在执行,忽略重复触发