RPC框架核心学习内容
RPC框架核心学习内容
线程池
1. 核心参数
corePoolSIze :核心池大小,未达到此参数会创建新的线程进行执行。达到此参数限制会放入等待队列中(小于maximunPoolSize)。
maximumPoolSize:最大能达到的数量限制,阻塞队列满且达到最大线程数的时候会根据抛弃策略进行丢弃。
keepAliveTime:当线程数大于核心时,多于的空闲线程最多存活时间。
workQueue:当线程舒服超过核心线程数的时候用于保存任务的队列。三种类型:*队列、有界队列、同步移交。
threadFactory:执行程序创建新线程时使用的工厂。
rejectedExecutionHandler:拒绝策略。提供四种拒绝策略。
2. workQueue
1. *队列(linkedBlockingQueue)
其实并不能算无限,这个队列的默认大小是Integer.MAXVALUE。newFixedThreadPool会采用此种队列。当任务耗时较长的时候,会无限在队列中创建等待任务,堆积大量的请求。可能会溢出造成OOM。大量任务被添加到这个*队列中,会导致cpu和内存飙升导致服务器挂掉。
2. 有界队列(ArrayBolckingQueue、PriorityBlockingQueue)
FIFO原则的 ArrayBolckingQueue 和优先级队列 PriorityBlockingQueue(优先级由任务的 Comparator 决定)。
线程池较小、有界队列较大时可减少内存消耗,降低cpu使用率和上下文切换,但是会限制系统吞吐量,可能会导致部分任务被丢失。
3. 同步移交队列(SynchronousQueue)
不是一种真正的队列,时一种线程间的移交机制。要将一个队列放入一种,必须要另一个线程正在等待接受这个元素。只有在使用*线程池(newCachedThreadPool)或者由饱和策略的时候才建议使用该队列。
newCachedThreadPool 的概念就是需要一个线程接受才能使任务顺利进入队列,否则的话就需要新启一个线程(刚开始的时候也就是会新创建线程后才会开始进行处理)。最大线程大小是Integer.MAXVALUE。任务太多时会创建大量的线程,可能会造成OOM。
所以阿里的规范里面不建议使用Executor,建议使用ThreadPoolExecutor自己创建。
3. 拒绝策略
1. AbortPolicy 中止策略
默认饱和策略。饱和时会抛出 RejectedExecutionException(RuntimeException),可捕获异常处理。
2. DiscardPolicy 抛弃策略
不做任何处理,直接抛弃任务
3. DiscardOldestPolicy抛弃旧任务策略
抛弃最老任务。抛弃掉队列头部的元素,再尝试提交任务。
如果使用的是优先级队列会导致优先级最高的任务被抛弃,不建议配合使用。
4. CallerRunsPolicy 调用者运行
使用调用者的线程来运行此任务。运行此任务期间无法提交新的任务。
动态代理
1. JDK动态代理
使用反射进行创建,被代理类需实现 InvocationHandler 接口
Method method = serviceClass.getMethod(methodName, parameterTypes);
method.setAccessible(true);
return method.invoke(serviceBean, parameters);
2. CGLib动态代理
Cglib动态代理执行代理方法效率之所以比JDK的高是因为Cglib采用了FastClass机制,它的原理简单来说就是:为代理类和被代理类各生成一个Class,这个Class会为代理类或被代理类的方法分配一个index(int类型)。
这个index当做一个入参,FastClass就可以直接定位要调用的方法直接进行调用,这样省去了反射调用,所以调用效率比JDK动态代理通过反射调用高。
FastClass serviceFastClass = FastClass.create(serviceClass);
// 其实这里里面也是使用的 index 来调用的,两者没有区别
FastMethod serviceFastMethod = serviceFastClass.getMethod(methodName, parameterTypes);
return serviceFastMethod.invoke(serviceBean, parameters);
//fastClass 使用methodIndex调用
int methodIndex = serviceFastClass.getIndex(methodName, parameterTypes);
return serviceFastClass.invoke(methodIndex, serviceBean, parameters);
// test2 是 test 的 fastClass
class Test{
public void f(){
System.out.println("f method");
}
public void g(){
System.out.println("g method");
}
}
class Test2{
public Object invoke(int index, Object o, Object[] ol){
Test t = (Test) o;
switch(index){
case 1:
t.f();
return null;
case 2:
t.g();
return null;
}
return null;
}
public int getIndex(String signature){
switch(signature.hashCode()){
case 3078479:
return 1;
case 3108270:
return 2;
}
return -1;
}
}
3. 区别
1.JDK动态代理是实现了被代理对象的接口,Cglib是继承了被代理对象。
2.JDK和Cglib都是在运行期生成字节码,JDK是直接写Class字节码,Cglib使用ASM框架写Class字节码,Cglib代理实现更复杂,生成代理类比JDK效率低。
3.JDK调用代理方法,是通过反射机制调用,Cglib是通过FastClass机制直接调用方法,Cglib执行效率更高。
推荐阅读
-
Spring 框架学习第三节:核心理念之一 —— IoC(控制反转)
-
rpc框架dubbo学习入门及环境搭建(spring boot+Kotlin)
-
python自动化测试—unittest框架四大核心概念学习
-
RPC框架Dubbo学习 --- Dubbo架构与实战(架构篇)
-
SSM框架整合核心内容
-
Spring框架(Framework)之IOC(控制反转)和AOP(面向切面编程)核心特性学习
-
Spring 框架学习第三节:核心理念之一 —— IoC(控制反转)
-
JS运动学习笔记 -- 任意值的运动框架(高/宽度,背景颜色,文本内容,透明度等) - Web学海无涯
-
JS运动学习笔记 任意值的运动框架(高/宽度,背景颜色,文本内容,透明度等)_html/css_WEB-ITnose
-
RPC框架核心学习内容