diff --git a/.idea/workspace.xml b/.idea/workspace.xml index d802d5e..5c73c58 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -1,8 +1,7 @@ - - + @@ -267,14 +266,7 @@ - - - - 1580965798400 - 1581102125245 @@ -612,7 +604,14 @@ - @@ -665,7 +664,6 @@ - @@ -690,7 +688,8 @@ - @@ -705,14 +704,14 @@ - + - - - + + + - + @@ -767,18 +766,18 @@ - + - + - + - + diff --git a/Rocket.md b/Rocket.md index 825dfeb..d81f262 100644 --- a/Rocket.md +++ b/Rocket.md @@ -269,6 +269,15 @@ HotSpot JVM把年轻代分为了三部分:1个Eden区和2个Survivor区(分 双亲委派的意思是如果一个类加载器需要加载类,那么首先它会把这个类请求委派给父类加载器去完成,每一层都是如此。一直递归到顶层,当父加载器无法完成这个请求时,子类才会尝试去加载。 + +### 双亲委派模型的"破坏" + +一个典型的例子便是JNDI服务,JNDI现在已经是Java的标准服务,它的代码由启动类加载器去加载(在JDK 1.3时放进去的rt.jar),但JNDI的目的就是对资源进行集中管理和查找,它需要调用由独立厂商实现并部署在应用程序的ClassPath下的JNDI接口提供者(SPI,Service Provider Interface)的代码,但启动类加载器不可能“认识”这些代码那该怎么办? + +为了解决这个问题,Java设计团队只好引入了一个不太优雅的设计:线程上下文类加载器(Thread Context ClassLoader)。这个类加载器可以通过java.lang.Thread类的 setContextClassLoaser()方法进行设置,如果创建线程时还未设置,它将会从父线程中继承 一个,如果在应用程序的全局范围内都没有设置过的话,那这个类加载器默认就是应用程序类加载器。 + +有了线程上下文类加载器,就可以做一些“舞弊”的事情了,JNDI服务使用这个线程上下 文类加载器去加载所需要的SPI代码,也就是父类加载器请求子类加载器去完成类加载的动 作,这种行为实际上就是打通了双亲委派模型的层次结构来逆向使用类加载器,实际上已经 违背了双亲委派模型的一般性原则,但这也是无可奈何的事情。Java中所有涉及SPI的加载动 作基本上都采用这种方式,例如JNDI、JDBC、JCE、JAXB和JBI等。 + ### JVM锁优化和膨胀过程 1. 自旋锁:自旋锁其实就是在拿锁时发现已经有线程拿了锁,自己如果去拿会阻塞自己,这个时候会选择进行一次忙循环尝试。也就是不停循环看是否能等到上个线程自己释放锁。自适应自旋锁指的是例如第一次设置最多自旋10次,结果在自旋的过程中成功获得了锁,那么下一次就可以设置成最多自旋20次。