• 总是套路留人心, JAVA提供的套路: LinkedHashMap实现LRU缓存; InvocationHandler实现动态代理; fork/join实现窃取算法


    1. LinkedHashMap实现LRU缓存

    LRU缓存核心是根据访问顺序排序, 自动移除队尾缓存, LinkedHashMap已经实现了这些要求:

    public LRUCache<K, V> extends LinkedHashMap<K, V> {
        private int cacheSize;
        
        public LRUCache(int cacheSize){
            super(16, 0.75, true);   // key1: true表示使用访问排序, 默认false表示插入排序 
    }
        @Override
        protected boolean removeEldestEntry(Map.Entry<k, V> eldest){
            return size() >= cacheSize;  //key2: 每次调用add后, 底层都会调用这个方法判断是否执行移除队尾元素, 通过重写这个方法来控制移除时机
    }
    }

    2.InvocationHandler实现动态代理

    手工为每一个类实现一个代理类称为静态代理, 缺点是即使代理的操作是一样的, 仍然要为每个类实现一个代理类, 代理操作代码不能复用

    //1.实现代理类
    public class MyInvocationHandler implements InvocationHandler {  
        private Object target;  
      
        MyInvocationHandler() {  
            super();  
        }  
      
        MyInvocationHandler(Object target) {  
            super();  
            this.target = target;  
        }  
      
        @Override  
        public Object invoke(Object o, Method method, Object[] args) throws Throwable {  
            if("getName".equals(method.getName())){  
                System.out.println("++++++before " + method.getName() + "++++++");  
                Object result = method.invoke(target, args);  
                System.out.println("++++++after " + method.getName() + "++++++");  
                return result;  
            }else{  
                Object result = method.invoke(target, args);  
                return result;  
            }  
        }  
    
    //2.获得代理对象
    (TargetInterface)Proxy.newProxyInstance(tarInterClass.getClassLoader(), tarInterClass.getInterface(), new MyInvocationHandler(tarObj));

    可以看出Proxy.newProxyInstance()获得的是对一个接口的代理, 这也是InvocationHandler动态代理的缺点:只能代理接口中的方法.

    想代理类中非implement接口的方法, 可以用第三方Cglib代理实现

    3.fork/join实现窃取模式

    窃取模式是一种升级版的生产者-消费者模式, 特点是线程在处理完自己的任务队列后, 回去其他线程的任务队列的末尾窃取任务来执行, 以提高效率.

    如果自己实现窃取模式:首先要一个线程池来执行任务, 其次要为每一个线程提供一个任务队列, 最后还要实现窃取其他队列的任务的功能. 幸运的是JAVA已经提供了实现.

    //1.编写任务类implement
    RecursiveAction    不反回结果, 相当于Runnable
    RecursiveTask        返回结果, 相当于Callable
    //2.获得线程池
    ForkJoinPool pool = new ForkJoinPool()
    //3.提交任务
        pool.execute()    异步执行命令
        pool.invoke()    执行命令并直接返回结果
        pool.submit()   执行任务并返回一个ForkJoinTask(Future)
    //4.子RecusiveAction
        fork()    //把自身添加到任务执行队列
        join()    //获得执行结果

    在compute()的实现中, 根据条件将任务分成更细的多个RecusiveTask, 就实现了分治法  

      

  • 相关阅读:
    英语阅读重点单词总结
    Redis 应用
    Python 列表[::-1]翻转
    golang数据类型
    golang变量
    k8s 容器控制台日志收集
    css显示模式
    css选择器
    css样式引入
    GIL锁
  • 原文地址:https://www.cnblogs.com/bianzy/p/6557378.html
Copyright © 2020-2023  润新知