欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

RPC框架核心学习内容

程序员文章站 2022-04-29 15:10:24
...

线程池

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执行效率更高。

相关标签: java